From 8105a5ee9f8c0bac2ba278c0bd25f4cea0980f9b Mon Sep 17 00:00:00 2001 From: "nweiz@google.com" Date: Fri, 18 Jul 2014 00:51:40 +0000 Subject: [PATCH 001/128] Extract out a source_span package from source_maps. This is just the first step; future CLs will add support for the new API to various packages currently using the old one. BUG=19930 R=sigmund@google.com Review URL: https://codereview.chromium.org//381363002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/source_span@38360 260f80e4-7a28-3924-810f-c04153c831b5 --- pkgs/source_span/CHANGELOG.md | 33 ++ pkgs/source_span/LICENSE | 26 ++ pkgs/source_span/README.md | 15 + pkgs/source_span/lib/source_span.dart | 11 + pkgs/source_span/lib/src/colors.dart | 13 + pkgs/source_span/lib/src/file.dart | 266 +++++++++++++ pkgs/source_span/lib/src/location.dart | 86 +++++ pkgs/source_span/lib/src/span.dart | 78 ++++ pkgs/source_span/lib/src/span_exception.dart | 43 +++ pkgs/source_span/lib/src/span_mixin.dart | 74 ++++ pkgs/source_span/lib/src/utils.dart | 39 ++ pkgs/source_span/pubspec.yaml | 12 + pkgs/source_span/test/file_message_test.dart | 100 +++++ pkgs/source_span/test/file_test.dart | 370 +++++++++++++++++++ pkgs/source_span/test/location_test.dart | 101 +++++ pkgs/source_span/test/span_test.dart | 256 +++++++++++++ pkgs/source_span/test/utils_test.dart | 51 +++ 17 files changed, 1574 insertions(+) create mode 100644 pkgs/source_span/CHANGELOG.md create mode 100644 pkgs/source_span/LICENSE create mode 100644 pkgs/source_span/README.md create mode 100644 pkgs/source_span/lib/source_span.dart create mode 100644 pkgs/source_span/lib/src/colors.dart create mode 100644 pkgs/source_span/lib/src/file.dart create mode 100644 pkgs/source_span/lib/src/location.dart create mode 100644 pkgs/source_span/lib/src/span.dart create mode 100644 pkgs/source_span/lib/src/span_exception.dart create mode 100644 pkgs/source_span/lib/src/span_mixin.dart create mode 100644 pkgs/source_span/lib/src/utils.dart create mode 100644 pkgs/source_span/pubspec.yaml create mode 100644 pkgs/source_span/test/file_message_test.dart create mode 100644 pkgs/source_span/test/file_test.dart create mode 100644 pkgs/source_span/test/location_test.dart create mode 100644 pkgs/source_span/test/span_test.dart create mode 100644 pkgs/source_span/test/utils_test.dart diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md new file mode 100644 index 000000000..04e4be2fd --- /dev/null +++ b/pkgs/source_span/CHANGELOG.md @@ -0,0 +1,33 @@ +# 1.0.0 + +This package was extracted from the +[`source_maps`](http://pub.dartlang.org/packages/source_maps) package, but the +API has many differences. Among them: + +* `Span` has been renamed to `SourceSpan` and `Location` has been renamed to + `SourceLocation` to clarify their purpose and maintain consistency with the + package name. Likewise, `SpanException` is now `SourceSpanException` and + `SpanFormatException` is not `SourceSpanFormatException`. + +* `FixedSpan` and `FixedLocation` have been rolled into the `Span` and + `Location` classes, respectively. + +* `SourceFile` is more aggressive about validating its arguments. Out-of-bounds + lines, columns, and offsets will now throw errors rather than be silently + clamped. + +* `SourceSpan.sourceUrl`, `SourceLocation.sourceUrl`, and `SourceFile.url` now + return `Uri` objects rather than `String`s. The constructors allow either + `String`s or `Uri`s. + +* `Span.getLocationMessage` and `SourceFile.getLocationMessage` are now + `SourceSpan.message` and `SourceFile.message`, respectively. Rather than + taking both a `useColor` and a `color` parameter, they now take a single + `color` parameter that controls both whether and which color is used. + +* `Span.isIdentifier` has been removed. This property doesn't make sense outside + of a source map context. + +* `SourceFileSegment` has been removed. This class wasn't widely used and was + inconsistent in its choice of which parameters were considered relative and + which absolute. diff --git a/pkgs/source_span/LICENSE b/pkgs/source_span/LICENSE new file mode 100644 index 000000000..5c60afea3 --- /dev/null +++ b/pkgs/source_span/LICENSE @@ -0,0 +1,26 @@ +Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/pkgs/source_span/README.md b/pkgs/source_span/README.md new file mode 100644 index 000000000..4e2547e28 --- /dev/null +++ b/pkgs/source_span/README.md @@ -0,0 +1,15 @@ +`source_span` is a library for tracking locations in source code. It's designed +to provide a standard representation for source code locations and spans so that +disparate packages can easily pass them among one another, and to make it easy +to generate human-friendly messages associated with a given piece of code. + +The most commonly-used class is the package's namesake, `SourceSpan`. It +represents a span of characters in some source file, and is often attached to an +object that has been parsed to indicate where it was parsed from. It provides +access to the text of the span via `SourceSpan.text` and can be used to produce +human-friendly messages using `SourceSpan.message()`. + +When parsing code from a file, `SourceFile` is useful. Not only does it provide +an efficient means of computing line and column numbers, `SourceFile.span()` +returns special `FileSpan`s that are able to provide more context for their +error messages. diff --git a/pkgs/source_span/lib/source_span.dart b/pkgs/source_span/lib/source_span.dart new file mode 100644 index 000000000..e9646b1fd --- /dev/null +++ b/pkgs/source_span/lib/source_span.dart @@ -0,0 +1,11 @@ +// Copyright (c) 2014, 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. + +library source_span; + +export "src/file.dart"; +export "src/location.dart"; +export "src/span.dart"; +export "src/span_exception.dart"; +export "src/span_mixin.dart"; diff --git a/pkgs/source_span/lib/src/colors.dart b/pkgs/source_span/lib/src/colors.dart new file mode 100644 index 000000000..274fc92af --- /dev/null +++ b/pkgs/source_span/lib/src/colors.dart @@ -0,0 +1,13 @@ +// Copyright (c) 2014, 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. + +// Color constants used for generating messages. +library source_span.colors; + +const String RED = '\u001b[31m'; + +const String YELLOW = '\u001b[33m'; + +const String NONE = '\u001b[0m'; + diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart new file mode 100644 index 000000000..0d2d6f6ca --- /dev/null +++ b/pkgs/source_span/lib/src/file.dart @@ -0,0 +1,266 @@ +// Copyright (c) 2014, 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. + +library source_span.file; + +import 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:path/path.dart' as p; + +import 'colors.dart' as colors; +import 'location.dart'; +import 'span.dart'; +import 'span_mixin.dart'; +import 'utils.dart'; + +// Constants to determine end-of-lines. +const int _LF = 10; +const int _CR = 13; + +/// A class representing a source file. +/// +/// This doesn't necessarily have to correspond to a file on disk, just a chunk +/// of text usually with a URL associated with it. +class SourceFile { + /// The URL where the source file is located. + /// + /// This may be null, indicating that the URL is unknown or unavailable. + final Uri url; + + /// An array of offsets for each line beginning in the file. + /// + /// Each offset refers to the first character *after* the newline. If the + /// source file has a trailing newline, the final offset won't actually be in + /// the file. + final _lineStarts = [0]; + + /// The code points of the characters in the file. + final Uint32List _decodedChars; + + /// The length of the file in characters. + int get length => _decodedChars.length; + + /// The number of lines in the file. + int get lines => _lineStarts.length; + + /// Creates a new source file from [text]. + /// + /// [url] may be either a [String], a [Uri], or `null`. + SourceFile(String text, {url}) + : this.decoded(text.runes, url: url); + + /// Creates a new source file from a list of decoded characters. + /// + /// [url] may be either a [String], a [Uri], or `null`. + SourceFile.decoded(Iterable decodedChars, {url}) + : url = url is String ? Uri.parse(url) : url, + _decodedChars = new Uint32List.fromList(decodedChars.toList()) { + for (var i = 0; i < _decodedChars.length; i++) { + var c = _decodedChars[i]; + 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; + } + if (c == _LF) _lineStarts.add(i + 1); + } + } + + /// Returns a span in [this] 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 - 1; + return new FileSpan._(this, location(start), location(end)); + } + + /// Returns a location in [this] at [offset]. + FileLocation location(int offset) => new FileLocation._(this, offset); + + /// Gets the 0-based line corresponding to [offset]. + int getLine(int offset) { + if (offset < 0) { + throw new RangeError("Offset may not be negative, was $offset."); + } else if (offset > length) { + throw new RangeError("Offset $offset must not be greater than the number " + "of characters in the file, $length."); + } + return binarySearch(_lineStarts, (o) => o > offset) - 1; + } + + /// Gets the 0-based column corresponding to [offset]. + /// + /// If [line] is passed, it's assumed to be the line containing [offset] and + /// is used to more efficiently compute the column. + int getColumn(int offset, {int line}) { + if (offset < 0) { + throw new RangeError("Offset may not be negative, was $offset."); + } else if (offset > length) { + throw new RangeError("Offset $offset must be not be greater than the " + "number of characters in the file, $length."); + } + + if (line == null) { + line = getLine(offset); + } else if (line < 0) { + throw new RangeError("Line may not be negative, was $line."); + } else if (line >= lines) { + throw new RangeError("Line $line must be less than the number of " + "lines in the file, $lines."); + } + + var lineStart = _lineStarts[line]; + if (lineStart > offset) { + throw new RangeError("Line $line comes after offset $offset."); + } + + return offset - lineStart; + } + + /// Gets the offset for a [line] and [column]. + /// + /// [column] defaults to 0. + int getOffset(int line, [int column]) { + if (column == null) column = 0; + + if (line < 0) { + throw new RangeError("Line may not be negative, was $line."); + } else if (line >= lines) { + throw new RangeError("Line $line must be less than the number of " + "lines in the file, $lines."); + } else if (column < 0) { + throw new RangeError("Column may not be negative, was $column."); + } + + var result = _lineStarts[line] + column; + if (result > length || + (line + 1 < lines && result >= _lineStarts[line + 1])) { + throw new RangeError("Line $line doesn't have $column columns."); + } + + return result; + } + + /// Returns the text of the file from [start] to [end] (exclusive). + /// + /// If [end] isn't passed, it defaults to the end of the file. + String getText(int start, [int end]) => + new String.fromCharCodes(_decodedChars.sublist(start, end)); +} + +/// A [SourceLocation] within a [SourceFile]. +/// +/// Unlike the base [SourceLocation], [FileLocation] lazily computes its line +/// and column values based on its offset and the contents of [file]. +/// +/// A [FileLocation] can be created using [SourceFile.location]. +class FileLocation extends SourceLocation { + /// The [file] that [this] belongs to. + final SourceFile file; + + Uri get sourceUrl => file.url; + int get line => file.getLine(offset); + int get column => file.getColumn(offset); + + FileLocation._(this.file, int offset) + : super(offset) { + if (offset > file.length) { + throw new RangeError("Offset $offset must not be greater than the number " + "of characters in the file, ${file.length}."); + } + } + + FileSpan pointSpan() => new FileSpan._(file, this, this); +} + +/// 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. +/// +/// A [FileSpan] can be created using [SourceFile.span]. +class FileSpan extends SourceSpanMixin { + /// The [file] that [this] belongs to. + final SourceFile file; + + final FileLocation start; + final FileLocation end; + + String get text => file.getText(start.offset, end.offset); + + FileSpan._(this.file, this.start, this.end) { + if (end.offset < start.offset) { + throw new ArgumentError('End $end must come after start $start.'); + } + } + + SourceSpan union(SourceSpan other) { + if (other is! FileSpan) return super.union(other); + + var span = expand(other); + var beginSpan = span.start == this.start ? this : other; + var endSpan = span.end == this.end ? this : other; + + if (beginSpan.end.compareTo(endSpan.start) < 0) { + throw new ArgumentError("Spans $this and $other are disjoint."); + } + + return span; + } + + /// Returns a new span that covers both [this] and [other]. + /// + /// 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) { + if (sourceUrl != other.sourceUrl) { + throw new ArgumentError("Source URLs \"${sourceUrl}\" and " + " \"${other.sourceUrl}\" don't match."); + } + + var start = min(this.start, other.start); + var end = max(this.end, other.end); + return new FileSpan._(file, start, end); + } + + String message(String message, {color}) { + if (color == true) color = colors.RED; + if (color == false) color = null; + + var line = start.line; + var column = start.column; + + var buffer = new StringBuffer(); + buffer.write('line ${start.line + 1}, column ${start.column + 1}'); + if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}'); + buffer.write(': $message\n'); + + var textLine = file.getText(file.getOffset(line), + line == file.lines - 1 ? null : file.getOffset(line + 1)); + + column = math.min(column, textLine.length - 1); + var toColumn = + math.min(column + end.offset - start.offset, textLine.length); + + if (color != null) { + buffer.write(textLine.substring(0, column)); + buffer.write(color); + buffer.write(textLine.substring(column, toColumn)); + buffer.write(colors.NONE); + buffer.write(textLine.substring(toColumn)); + } else { + buffer.write(textLine); + } + if (!textLine.endsWith('\n')) buffer.write('\n'); + + buffer.write(' ' * column); + if (color != null) buffer.write(color); + buffer.write('^' * math.max(toColumn - column, 1)); + if (color != null) buffer.write(colors.NONE); + return buffer.toString(); + } +} diff --git a/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart new file mode 100644 index 000000000..41f251898 --- /dev/null +++ b/pkgs/source_span/lib/src/location.dart @@ -0,0 +1,86 @@ +// Copyright (c) 2014, 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. + +library source_span.location; + +import 'span.dart'; + +// A class that describes a single location within a source file. +class SourceLocation implements Comparable { + /// URL of the source containing this location. + /// + /// This may be null, indicating that the source URL is unknown or + /// unavailable. + final Uri sourceUrl; + + /// The 0-based offset of this location in the source. + final int offset; + + /// The 0-based line of this location in the source. + final int line; + + /// The 0-based column of this location in the source + final int column; + + /// Returns a representation of this location in the `source:line:column` + /// format used by text editors. + /// + /// This prints 1-based lines and columns. + String get toolString { + var source = sourceUrl == null ? 'unknown source' : sourceUrl; + return '$source:${line + 1}:${column + 1}'; + } + + /// Creates a new location indicating [offset] within [sourceUrl]. + /// + /// [line] and [column] default to assuming the source is a single line. This + /// 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, + line = line == null ? 0 : line, + column = column == null ? offset : column { + if (this.offset < 0) { + throw new RangeError("Offset may not be negative, was $offset."); + } else if (this.line < 0) { + throw new RangeError("Line may not be negative, was $line."); + } else if (this.column < 0) { + throw new RangeError("Column may not be negative, was $column."); + } + } + + /// 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 new ArgumentError("Source URLs \"${sourceUrl}\" and " + "\"${other.sourceUrl}\" don't match."); + } + return (offset - other.offset).abs(); + } + + /// Returns a span that covers only a single point: this location. + SourceSpan pointSpan() => new SourceSpan(this, this, ""); + + /// Compares two locations. + /// + /// [other] must have the same source URL as [this]. + int compareTo(SourceLocation other) { + if (sourceUrl != other.sourceUrl) { + throw new ArgumentError("Source URLs \"${sourceUrl}\" and " + "\"${other.sourceUrl}\" don't match."); + } + return offset - other.offset; + } + + bool operator ==(SourceLocation other) => + sourceUrl == other.sourceUrl && offset == other.offset; + + int get hashCode => sourceUrl.hashCode + offset; + + String toString() => '<$runtimeType: $offset $toolString>'; +} diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart new file mode 100644 index 000000000..9f150482c --- /dev/null +++ b/pkgs/source_span/lib/src/span.dart @@ -0,0 +1,78 @@ +// Copyright (c) 2014, 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. + +library source_span.span; + +import 'location.dart'; +import 'span_mixin.dart'; + +/// A class that describes a segment of source text. +abstract class SourceSpan implements Comparable { + /// The start location of this span. + final SourceLocation start; + + /// The end location of this span, exclusive. + final SourceLocation end; + + /// The source text for this span. + final String text; + + /// The URL of the source (typically a file) of this span. + /// + /// This may be null, indicating that the source URL is unknown or + /// unavailable. + final Uri sourceUrl; + + /// The length of this span, in characters. + final int length; + + /// Creates a new span from [start] to [end] (exclusive) containing [text]. + /// + /// [start] and [end] must have the same source URL and [start] must come + /// before [end]. [text] must have a number of characters equal to the + /// distance between [start] and [end]. + factory SourceSpan(SourceLocation start, SourceLocation end, String text) => + new SourceSpanBase(start, end, text); + + /// 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]. + SourceSpan union(SourceSpan other); + + /// Compares two spans. + /// + /// [other] must have the same source URL as [this]. This orders spans by + /// [start] then [length]. + int compareTo(SourceSpan other); + + /// Formats [message] in a human-friendly way associated with this span. + /// + /// [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 + /// 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. + String message(String message, {color}); +} + +/// A base class for source spans with [start], [end], and [text] known at +/// construction time. +class SourceSpanBase extends SourceSpanMixin { + final SourceLocation start; + final SourceLocation end; + final String text; + + SourceSpanBase(this.start, this.end, this.text) { + if (end.sourceUrl != start.sourceUrl) { + throw new ArgumentError("Source URLs \"${start.sourceUrl}\" and " + " \"${end.sourceUrl}\" don't match."); + } else if (end.offset < start.offset) { + throw new ArgumentError('End $end must come after start $start.'); + } else if (text.length != start.distance(end)) { + throw new ArgumentError('Text "$text" must be ${start.distance(end)} ' + 'characters long.'); + } + } +} diff --git a/pkgs/source_span/lib/src/span_exception.dart b/pkgs/source_span/lib/src/span_exception.dart new file mode 100644 index 000000000..af642413b --- /dev/null +++ b/pkgs/source_span/lib/src/span_exception.dart @@ -0,0 +1,43 @@ +// Copyright (c) 2014, 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. + +library source_span.span_exception; + +import 'span.dart'; + +/// A class for exceptions that have source span information attached. +class SourceSpanException implements Exception { + /// A message describing the exception. + final String message; + + /// The span associated with this exception. + /// + /// This may be `null` if the source location can't be determined. + final SourceSpan span; + + SourceSpanException(this.message, this.span); + + /// 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 + /// 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. + String toString({color}) { + if (span == null) return message; + return "Error on " + span.message(message, color: color); + } +} + +/// A [SourceSpanException] that's also a [FormatException]. +class SourceSpanFormatException extends SourceSpanException + implements FormatException { + final source; + + int get position => span == null ? null : span.start.offset; + + SourceSpanFormatException(String message, SourceSpan span, [this.source]) + : super(message, span); +} diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart new file mode 100644 index 000000000..95a720aae --- /dev/null +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -0,0 +1,74 @@ +// Copyright (c) 2014, 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. + +library source_span.span_mixin; + +import 'package:path/path.dart' as p; + +import 'colors.dart' as colors; +import 'span.dart'; +import 'utils.dart'; + +/// A mixin for easily implementing [SourceSpan]. +/// +/// This implements the [SourceSpan] methods in terms of [start], [end], and +/// [text]. This assumes that [start] and [end] have the same source URL, that +/// [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 { + Uri get sourceUrl => start.sourceUrl; + int get length => end.offset - start.offset; + + int compareTo(SourceSpan other) { + int d = start.compareTo(other.start); + return d == 0 ? end.compareTo(other.end) : d; + } + + SourceSpan union(SourceSpan other) { + if (sourceUrl != other.sourceUrl) { + throw new 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; + + if (beginSpan.end.compareTo(endSpan.start) < 0) { + throw new ArgumentError("Spans $this and $other are disjoint."); + } + + var text = beginSpan.text + + endSpan.text.substring(beginSpan.end.distance(endSpan.start)); + return new SourceSpan(start, end, text); + } + + String message(String message, {color}) { + if (color == true) color = colors.RED; + if (color == false) color = null; + + var buffer = new StringBuffer(); + buffer.write('line ${start.line + 1}, column ${start.column + 1}'); + if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}'); + buffer.write(': $message'); + if (length == 0) return buffer.toString(); + + buffer.write("\n"); + var textLine = text.split("\n").first; + if (color != null) buffer.write(color); + buffer.write(textLine); + buffer.write("\n"); + buffer.write('^' * textLine.length); + if (color != null) buffer.write(colors.NONE); + return buffer.toString(); + } + + bool operator ==(SourceSpan other) => + start == other.start && end == other.end; + + int get hashCode => start.hashCode + (31 * end.hashCode); + + String toString() => '<$runtimeType: from $start to $end "$text">'; +} diff --git a/pkgs/source_span/lib/src/utils.dart b/pkgs/source_span/lib/src/utils.dart new file mode 100644 index 000000000..4a8eb551e --- /dev/null +++ b/pkgs/source_span/lib/src/utils.dart @@ -0,0 +1,39 @@ +// Copyright (c) 2014, 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. + +library source_span.utils; + +/// Returns the minimum of [obj1] and [obj2] according to +/// [Comparable.compareTo]. +Comparable min(Comparable obj1, Comparable obj2) => + obj1.compareTo(obj2) > 0 ? obj2 : obj1; + +/// Returns the maximum of [obj1] and [obj2] according to +/// [Comparable.compareTo]. +Comparable max(Comparable obj1, Comparable obj2) => + obj1.compareTo(obj2) > 0 ? obj1 : obj2; + +/// Find the first entry in a sorted [list] that matches a monotonic predicate. +/// +/// Given a result `n`, that all items before `n` will not match, `n` matches, +/// and all items after `n` match too. The result is -1 when there are no +/// items, 0 when all items match, and list.length when none does. +int binarySearch(List list, bool matches(item)) { + if (list.length == 0) return -1; + if (matches(list.first)) return 0; + if (!matches(list.last)) return list.length; + + int min = 0; + int max = list.length - 1; + while (min < max) { + var half = min + ((max - min) ~/ 2); + if (matches(list[half])) { + max = half; + } else { + min = half + 1; + } + } + return max; +} + diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml new file mode 100644 index 000000000..66e5811ac --- /dev/null +++ b/pkgs/source_span/pubspec.yaml @@ -0,0 +1,12 @@ +name: source_span + +version: 1.0.0 +author: Dart Team +description: A library for identifying source spans and locations. +homepage: http://www.dartlang.org +dependencies: + path: '>=1.2.0 <2.0.0' +environment: + sdk: '>=0.8.10+6 <2.0.0' +dev_dependencies: + unittest: '>=0.9.0 <0.10.0' diff --git a/pkgs/source_span/test/file_message_test.dart b/pkgs/source_span/test/file_message_test.dart new file mode 100644 index 000000000..18b34e71b --- /dev/null +++ b/pkgs/source_span/test/file_message_test.dart @@ -0,0 +1,100 @@ +// Copyright (c) 2014, 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:unittest/unittest.dart'; +import 'package:source_span/source_span.dart'; +import 'package:source_span/src/colors.dart' as colors; + +main() { + var file; + setUp(() { + file = new SourceFile(""" +foo bar baz +whiz bang boom +zip zap zop +""", url: "foo.dart"); + }); + + test("points to the span in the source", () { + expect(file.span(4, 7).message("oh no"), equals(""" +line 1, column 5 of foo.dart: oh no +foo bar baz + ^^^""")); + }); + + test("gracefully handles a missing source URL", () { + var span = new SourceFile("foo bar baz").span(4, 7); + expect(span.message("oh no"), equals(""" +line 1, column 5: oh no +foo bar baz + ^^^""")); + }); + + test("highlights the first line of a multiline span", () { + expect(file.span(4, 20).message("oh no"), equals(""" +line 1, column 5 of foo.dart: oh no +foo bar baz + ^^^^^^^^""")); + }); + + test("works for a point span", () { + expect(file.location(4).pointSpan().message("oh no"), equals(""" +line 1, column 5 of foo.dart: oh no +foo bar baz + ^""")); + }); + + test("works for a point span at the end of a line", () { + expect(file.location(11).pointSpan().message("oh no"), equals(""" +line 1, column 12 of foo.dart: oh no +foo bar baz + ^""")); + }); + + test("works for a point span at the end of the file", () { + expect(file.location(38).pointSpan().message("oh no"), equals(""" +line 3, column 12 of foo.dart: oh no +zip zap zop + ^""")); + }); + + test("works for a point span in an empty file", () { + expect(new SourceFile("").location(0).pointSpan().message("oh no"), + equals(""" +line 1, column 1: oh no + +^""")); + }); + + test("works for a single-line file without a newline", () { + expect(new SourceFile("foo bar").span(0, 7).message("oh no"), + equals(""" +line 1, column 1: oh no +foo bar +^^^^^^^""")); + }); + + group("colors", () { + test("doesn't colorize if color is false", () { + expect(file.span(4, 7).message("oh no", color: false), equals(""" +line 1, column 5 of foo.dart: oh no +foo bar baz + ^^^""")); + }); + + test("colorizes if color is true", () { + expect(file.span(4, 7).message("oh no", color: true), equals(""" +line 1, column 5 of foo.dart: oh no +foo ${colors.RED}bar${colors.NONE} baz + ${colors.RED}^^^${colors.NONE}""")); + }); + + test("uses the given color if it's passed", () { + expect(file.span(4, 7).message("oh no", color: colors.YELLOW), equals(""" +line 1, column 5 of foo.dart: oh no +foo ${colors.YELLOW}bar${colors.NONE} baz + ${colors.YELLOW}^^^${colors.NONE}""")); + }); + }); +} diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart new file mode 100644 index 000000000..114a17e44 --- /dev/null +++ b/pkgs/source_span/test/file_test.dart @@ -0,0 +1,370 @@ +// Copyright (c) 2014, 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:unittest/unittest.dart'; +import 'package:source_span/source_span.dart'; + +main() { + var file; + setUp(() { + file = new SourceFile(""" +foo bar baz +whiz bang boom +zip zap zop""", url: "foo.dart"); + }); + + group("errors", () { + group("for span()", () { + test("end must come after start", () { + expect(() => file.span(10, 5), throwsArgumentError); + }); + + test("start may not be negative", () { + expect(() => file.span(-1, 5), throwsRangeError); + }); + + test("end may not be outside the file", () { + expect(() => file.span(10, 100), throwsRangeError); + }); + }); + + group("for location()", () { + test("offset may not be negative", () { + expect(() => file.location(-1), throwsRangeError); + }); + + test("offset may not be outside the file", () { + expect(() => file.location(100), throwsRangeError); + }); + }); + + group("for getLine()", () { + test("offset may not be negative", () { + expect(() => file.getLine(-1), throwsRangeError); + }); + + test("offset may not be outside the file", () { + expect(() => file.getLine(100), throwsRangeError); + }); + }); + + group("for getColumn()", () { + test("offset may not be negative", () { + expect(() => file.getColumn(-1), throwsRangeError); + }); + + test("offset may not be outside the file", () { + expect(() => file.getColumn(100), throwsRangeError); + }); + + test("line may not be negative", () { + expect(() => file.getColumn(1, line: -1), throwsRangeError); + }); + + test("line may not be outside the file", () { + expect(() => file.getColumn(1, line: 100), throwsRangeError); + }); + + test("line must be accurate", () { + expect(() => file.getColumn(1, line: 1), throwsRangeError); + }); + }); + + group("getOffset()", () { + test("line may not be negative", () { + expect(() => file.getOffset(-1), throwsRangeError); + }); + + test("column may not be negative", () { + expect(() => file.getOffset(1, -1), throwsRangeError); + }); + + test("line may not be outside the file", () { + expect(() => file.getOffset(100), throwsRangeError); + }); + + test("column may not be outside the file", () { + expect(() => file.getOffset(2, 100), throwsRangeError); + }); + + test("column may not be outside the line", () { + expect(() => file.getOffset(1, 20), throwsRangeError); + }); + }); + + group("for getText()", () { + test("end must come after start", () { + expect(() => file.getText(10, 5), throwsArgumentError); + }); + + test("start may not be negative", () { + expect(() => file.getText(-1, 5), throwsRangeError); + }); + + test("end may not be outside the file", () { + expect(() => file.getText(10, 100), throwsRangeError); + }); + }); + + group("for span().union()", () { + test("source URLs must match", () { + var other = new SourceSpan( + new SourceLocation(10), new SourceLocation(11), "_"); + + expect(() => file.span(9, 10).union(other), throwsArgumentError); + }); + + test("spans may not be disjoint", () { + expect(() => file.span(9, 10).union(file.span(11, 12)), + throwsArgumentError); + }); + }); + + test("for span().expand() source URLs must match", () { + var other = new SourceFile(""" +foo bar baz +whiz bang boom +zip zap zop""", url: "bar.dart").span(10, 11); + + expect(() => file.span(9, 10).expand(other), throwsArgumentError); + }); + }); + + test('fields work correctly', () { + expect(file.url, equals(Uri.parse("foo.dart"))); + expect(file.lines, equals(3)); + expect(file.length, equals(38)); + }); + + group("new SourceFile()", () { + test("handles CRLF correctly", () { + expect(new SourceFile("foo\r\nbar").getLine(6), equals(1)); + }); + + test("handles a lone CR correctly", () { + expect(new SourceFile("foo\rbar").getLine(5), equals(1)); + }); + }); + + group("span()", () { + test("returns a span between the given offsets", () { + var 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); + expect(span.start, equals(file.location(5))); + expect(span.end, equals(file.location(file.length - 1))); + }); + }); + + group("getLine()", () { + test("works for a middle character on the line", () { + expect(file.getLine(15), equals(1)); + }); + + test("works for the first character of a line", () { + expect(file.getLine(12), equals(1)); + }); + + test("works for a newline character", () { + expect(file.getLine(11), equals(0)); + }); + + test("works for the last offset", () { + expect(file.getLine(file.length), equals(2)); + }); + }); + + group("getColumn()", () { + test("works for a middle character on the line", () { + expect(file.getColumn(15), equals(3)); + }); + + test("works for the first character of a line", () { + expect(file.getColumn(12), equals(0)); + }); + + test("works for a newline character", () { + expect(file.getColumn(11), equals(11)); + }); + + test("works when line is passed as well", () { + expect(file.getColumn(12, line: 1), equals(0)); + }); + + test("works for the last offset", () { + expect(file.getColumn(file.length), equals(11)); + }); + }); + + group("getOffset()", () { + test("works for a middle character on the line", () { + expect(file.getOffset(1, 3), equals(15)); + }); + + test("works for the first character of a line", () { + expect(file.getOffset(1), equals(12)); + }); + + test("works for a newline character", () { + expect(file.getOffset(0, 11), equals(11)); + }); + + test("works for the last offset", () { + expect(file.getOffset(2, 11), equals(file.length)); + }); + }); + + group("getText()", () { + test("returns a substring of the source", () { + expect(file.getText(8, 15), equals("baz\nwhi")); + }); + + test("end defaults to the end of the file", () { + expect(file.getText(20), equals("g boom\nzip zap zop")); + }); + }); + + group("FileLocation", () { + test("reports the correct line number", () { + expect(file.location(15).line, equals(1)); + }); + + test("reports the correct column number", () { + expect(file.location(15).column, equals(3)); + }); + + test("pointSpan() returns a FileSpan", () { + var location = file.location(15); + var span = location.pointSpan(); + expect(span, new isInstanceOf()); + expect(span.start, equals(location)); + expect(span.end, equals(location)); + expect(span.text, isEmpty); + }); + }); + + group("FileSpan", () { + test("text returns a substring of the source", () { + expect(file.span(8, 15).text, equals("baz\nwhi")); + }); + + group("union()", () { + var 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); + 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); + 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); + 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); + 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); + expect(span.union(other), equals(span)); + }); + + test("works with an external overlapping span", () { + var other = file.span(0, 16); + expect(span.union(other), equals(other)); + }); + + test("returns a FileSpan for a FileSpan input", () { + expect(span.union(file.span(0, 5)), new isInstanceOf()); + }); + + test("returns a base SourceSpan for a SourceSpan input", () { + var other = new SourceSpan( + new SourceLocation(0, sourceUrl: "foo.dart"), + new SourceLocation(5, sourceUrl: "foo.dart"), + "hey, "); + var result = span.union(other); + expect(result, isNot(new isInstanceOf())); + expect(result.start, equals(other.start)); + expect(result.end, equals(span.end)); + expect(result.text, equals("hey, ar baz\n")); + }); + }); + + group("expand()", () { + var 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); + 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); + 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); + 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); + 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); + expect(span.expand(other), equals(span)); + }); + + test("works with an external overlapping span", () { + var other = file.span(0, 16); + expect(span.expand(other), equals(other)); + }); + }); + }); +} \ No newline at end of file diff --git a/pkgs/source_span/test/location_test.dart b/pkgs/source_span/test/location_test.dart new file mode 100644 index 000000000..1eedec43a --- /dev/null +++ b/pkgs/source_span/test/location_test.dart @@ -0,0 +1,101 @@ +// Copyright (c) 2014, 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:unittest/unittest.dart'; +import 'package:source_span/source_span.dart'; + +main() { + var location; + setUp(() { + location = new SourceLocation(15, + line: 2, column: 6, sourceUrl: "foo.dart"); + }); + + group('errors', () { + group('for new SourceLocation()', () { + test('offset may not be negative', () { + expect(() => new SourceLocation(-1), throwsRangeError); + }); + + test('line may not be negative', () { + expect(() => new SourceLocation(0, line: -1), throwsRangeError); + }); + + test('column may not be negative', () { + expect(() => new SourceLocation(0, column: -1), throwsRangeError); + }); + }); + + test('for distance() source URLs must match', () { + expect(() => location.distance(new SourceLocation(0)), + throwsArgumentError); + }); + + test('for compareTo() source URLs must match', () { + expect(() => location.compareTo(new SourceLocation(0)), + throwsArgumentError); + }); + }); + + test('fields work correctly', () { + expect(location.sourceUrl, equals(Uri.parse("foo.dart"))); + expect(location.offset, equals(15)); + expect(location.line, equals(2)); + expect(location.column, equals(6)); + }); + + group('toolString', () { + test('returns a computer-readable representation', () { + expect(location.toolString, equals('foo.dart:3:7')); + }); + + test('gracefully handles a missing source URL', () { + var location = new SourceLocation(15, line: 2, column: 6); + expect(location.toolString, equals('unknown source:3:7')); + }); + }); + + test("distance returns the absolute distance between locations", () { + var other = new 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(); + expect(span.start, equals(location)); + expect(span.end, equals(location)); + expect(span.text, isEmpty); + }); + + group("compareTo()", () { + test("sorts by offset", () { + var other = new SourceLocation(20, sourceUrl: "foo.dart"); + expect(location.compareTo(other), lessThan(0)); + expect(other.compareTo(location), greaterThan(0)); + }); + + test("considers equal locations equal", () { + expect(location.compareTo(location), equals(0)); + }); + }); + + + group("equality", () { + test("two locations with the same offset and source are equal", () { + var other = new SourceLocation(15, sourceUrl: "foo.dart"); + expect(location, equals(other)); + }); + + test("a different offset isn't equal", () { + var other = new SourceLocation(10, sourceUrl: "foo.dart"); + expect(location, isNot(equals(other))); + }); + + test("a different source isn't equal", () { + var other = new SourceLocation(15, sourceUrl: "bar.dart"); + expect(location, isNot(equals(other))); + }); + }); +} diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart new file mode 100644 index 000000000..c62753b1a --- /dev/null +++ b/pkgs/source_span/test/span_test.dart @@ -0,0 +1,256 @@ +// Copyright (c) 2014, 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:unittest/unittest.dart'; +import 'package:source_span/source_span.dart'; +import 'package:source_span/src/colors.dart' as colors; + +main() { + var span; + setUp(() { + span = new SourceSpan( + new SourceLocation(5, sourceUrl: "foo.dart"), + new SourceLocation(12, sourceUrl: "foo.dart"), + "foo bar"); + }); + + group('errors', () { + group('for new SourceSpan()', () { + test('source URLs must match', () { + var start = new SourceLocation(0, sourceUrl: "foo.dart"); + var end = new SourceLocation(1, sourceUrl: "bar.dart"); + expect(() => new SourceSpan(start, end, "_"), throwsArgumentError); + }); + + test('end must come after start', () { + var start = new SourceLocation(1); + var end = new SourceLocation(0); + expect(() => new SourceSpan(start, end, "_"), throwsArgumentError); + }); + + test('text must be the right length', () { + var start = new SourceLocation(0); + var end = new SourceLocation(1); + expect(() => new SourceSpan(start, end, "abc"), throwsArgumentError); + }); + }); + + group('for union()', () { + test('source URLs must match', () { + var other = new SourceSpan( + new SourceLocation(12, sourceUrl: "bar.dart"), + new SourceLocation(13, sourceUrl: "bar.dart"), + "_"); + + expect(() => span.union(other), throwsArgumentError); + }); + + test('spans may not be disjoint', () { + var other = new SourceSpan( + new SourceLocation(13, sourceUrl: 'foo.dart'), + new SourceLocation(14, sourceUrl: 'foo.dart'), + "_"); + + expect(() => span.union(other), throwsArgumentError); + }); + }); + + test('for compareTo() source URLs must match', () { + var other = new SourceSpan( + new SourceLocation(12, sourceUrl: "bar.dart"), + new SourceLocation(13, sourceUrl: "bar.dart"), + "_"); + + expect(() => span.compareTo(other), throwsArgumentError); + }); + }); + + test('fields work correctly', () { + expect(span.start, equals(new SourceLocation(5, sourceUrl: "foo.dart"))); + expect(span.end, equals(new SourceLocation(12, sourceUrl: "foo.dart"))); + expect(span.sourceUrl, equals(Uri.parse("foo.dart"))); + expect(span.length, equals(7)); + }); + + group("union()", () { + test("works with a preceding adjacent span", () { + var other = new SourceSpan( + new SourceLocation(0, sourceUrl: "foo.dart"), + new SourceLocation(5, sourceUrl: "foo.dart"), + "hey, "); + + var 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 = new SourceSpan( + new SourceLocation(0, sourceUrl: "foo.dart"), + new SourceLocation(8, sourceUrl: "foo.dart"), + "hey, foo"); + + var 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 = new SourceSpan( + new SourceLocation(12, sourceUrl: "foo.dart"), + new SourceLocation(16, sourceUrl: "foo.dart"), + " baz"); + + var 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 = new SourceSpan( + new SourceLocation(9, sourceUrl: "foo.dart"), + new SourceLocation(16, sourceUrl: "foo.dart"), + "bar baz"); + + var 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 = new SourceSpan( + new SourceLocation(7, sourceUrl: "foo.dart"), + new SourceLocation(10, sourceUrl: "foo.dart"), + "o b"); + + expect(span.union(other), equals(span)); + }); + + test("works with an external overlapping span", () { + var other = new SourceSpan( + new SourceLocation(0, sourceUrl: "foo.dart"), + new SourceLocation(16, sourceUrl: "foo.dart"), + "hey, foo bar baz"); + + expect(span.union(other), equals(other)); + }); + }); + + group("message()", () { + test("prints the text being described", () { + expect(span.message("oh no"), equals(""" +line 1, column 6 of foo.dart: oh no +foo bar +^^^^^^^""")); + }); + + test("gracefully handles a missing source URL", () { + var span = new SourceSpan( + new SourceLocation(5), new SourceLocation(12), "foo bar"); + + expect(span.message("oh no"), equalsIgnoringWhitespace(""" +line 1, column 6: oh no +foo bar +^^^^^^^""")); + }); + + test("gracefully handles empty text", () { + var span = new SourceSpan( + new SourceLocation(5), new SourceLocation(5), ""); + + expect(span.message("oh no"), + equals("line 1, column 6: oh no")); + }); + + test("doesn't colorize if color is false", () { + expect(span.message("oh no", color: false), equals(""" +line 1, column 6 of foo.dart: oh no +foo bar +^^^^^^^""")); + }); + + test("colorizes if color is true", () { + expect(span.message("oh no", color: true), + equals(""" +line 1, column 6 of foo.dart: oh no +${colors.RED}foo bar +^^^^^^^${colors.NONE}""")); + }); + + test("uses the given color if it's passed", () { + expect(span.message("oh no", color: colors.YELLOW), equals(""" +line 1, column 6 of foo.dart: oh no +${colors.YELLOW}foo bar +^^^^^^^${colors.NONE}""")); + }); + }); + + group("compareTo()", () { + test("sorts by start location first", () { + var other = new SourceSpan( + new SourceLocation(6, sourceUrl: "foo.dart"), + new SourceLocation(14, sourceUrl: "foo.dart"), + "oo bar b"); + + expect(span.compareTo(other), lessThan(0)); + expect(other.compareTo(span), greaterThan(0)); + }); + + test("sorts by length second", () { + var other = new SourceSpan( + new SourceLocation(5, sourceUrl: "foo.dart"), + new SourceLocation(14, sourceUrl: "foo.dart"), + "foo bar b"); + + expect(span.compareTo(other), lessThan(0)); + expect(other.compareTo(span), greaterThan(0)); + }); + + test("considers equal spans equal", () { + expect(span.compareTo(span), equals(0)); + }); + }); + + group("equality", () { + test("two spans with the same locations are equal", () { + var other = new SourceSpan( + new SourceLocation(5, sourceUrl: "foo.dart"), + new SourceLocation(12, sourceUrl: "foo.dart"), + "foo bar"); + + expect(span, equals(other)); + }); + + test("a different start isn't equal", () { + var other = new SourceSpan( + new SourceLocation(0, sourceUrl: "foo.dart"), + new SourceLocation(12, sourceUrl: "foo.dart"), + "hey, foo bar"); + + expect(span, isNot(equals(other))); + }); + + test("a different end isn't equal", () { + var other = new SourceSpan( + new SourceLocation(5, sourceUrl: "foo.dart"), + new SourceLocation(16, sourceUrl: "foo.dart"), + "foo bar baz"); + + expect(span, isNot(equals(other))); + }); + + test("a different source URL isn't equal", () { + var other = new SourceSpan( + new SourceLocation(5, sourceUrl: "bar.dart"), + new SourceLocation(12, sourceUrl: "bar.dart"), + "foo bar"); + + expect(span, isNot(equals(other))); + }); + }); +} diff --git a/pkgs/source_span/test/utils_test.dart b/pkgs/source_span/test/utils_test.dart new file mode 100644 index 000000000..39211111e --- /dev/null +++ b/pkgs/source_span/test/utils_test.dart @@ -0,0 +1,51 @@ +// Copyright (c) 2013, 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:unittest/unittest.dart'; +import 'package:source_span/src/utils.dart'; + +main() { + group('binary search', () { + test('empty', () { + expect(binarySearch([], (x) => true), -1); + }); + + test('single element', () { + expect(binarySearch([1], (x) => true), 0); + expect(binarySearch([1], (x) => false), 1); + }); + + test('no matches', () { + var list = [1, 2, 3, 4, 5, 6, 7]; + expect(binarySearch(list, (x) => false), list.length); + }); + + test('all match', () { + var list = [1, 2, 3, 4, 5, 6, 7]; + expect(binarySearch(list, (x) => true), 0); + }); + + test('compare with linear search', () { + for (int size = 0; size < 100; size++) { + var list = []; + for (int i = 0; i < size; i++) { + list.add(i); + } + for (int pos = 0; pos <= size; pos++) { + expect(binarySearch(list, (x) => x >= pos), + _linearSearch(list, (x) => x >= pos)); + } + } + }); + }); +} + +_linearSearch(list, predicate) { + if (list.length == 0) return -1; + for (int i = 0; i < list.length; i++) { + if (predicate(list[i])) return i; + } + return list.length; +} + From 4990ab23d701848fae0e800399042d671307706c Mon Sep 17 00:00:00 2001 From: "lrn@google.com" Date: Fri, 18 Jul 2014 09:25:48 +0000 Subject: [PATCH 002/128] Change "FormatException.position" to be named "offset". Address comments on SpanFormatException changes. R=nweiz@google.com Committed: https://code.google.com/p/dart/source/detail?r=38373 Committed: https://code.google.com/p/dart/source/detail?r=38378 Review URL: https://codereview.chromium.org//396603003 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/source_span@38379 260f80e4-7a28-3924-810f-c04153c831b5 --- pkgs/source_span/lib/src/span_exception.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/source_span/lib/src/span_exception.dart b/pkgs/source_span/lib/src/span_exception.dart index af642413b..36f248832 100644 --- a/pkgs/source_span/lib/src/span_exception.dart +++ b/pkgs/source_span/lib/src/span_exception.dart @@ -36,7 +36,7 @@ class SourceSpanFormatException extends SourceSpanException implements FormatException { final source; - int get position => span == null ? null : span.start.offset; + int get offset => span == null ? null : span.start.offset; SourceSpanFormatException(String message, SourceSpan span, [this.source]) : super(message, span); From 3db3d336c333afca2caf512d202bc9bc5fcb464f Mon Sep 17 00:00:00 2001 From: "nweiz@google.com" Date: Fri, 7 Nov 2014 00:30:59 +0000 Subject: [PATCH 003/128] Use a more compact internal representation for FileSpan. R=rnystrom@google.com Review URL: https://codereview.chromium.org//706133002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/source_span@41591 260f80e4-7a28-3924-810f-c04153c831b5 --- pkgs/source_span/CHANGELOG.md | 4 ++++ pkgs/source_span/lib/src/file.dart | 30 +++++++++++++++++++++--------- pkgs/source_span/pubspec.yaml | 2 +- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 04e4be2fd..e5190bcd9 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.0.1 + +* Use a more compact internal representation for `FileSpan`. + # 1.0.0 This package was extracted from the diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 0d2d6f6ca..5680733d4 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -73,7 +73,7 @@ class SourceFile { /// If [end] isn't passed, it defaults to the end of the file. FileSpan span(int start, [int end]) { if (end == null) end = length - 1; - return new FileSpan._(this, location(start), location(end)); + return new FileSpan._(this, start, end); } /// Returns a location in [this] at [offset]. @@ -172,7 +172,7 @@ class FileLocation extends SourceLocation { } } - FileSpan pointSpan() => new FileSpan._(file, this, this); + FileSpan pointSpan() => new FileSpan._(file, offset, offset); } /// A [SourceSpan] within a [SourceFile]. @@ -187,14 +187,26 @@ class FileSpan extends SourceSpanMixin { /// The [file] that [this] belongs to. final SourceFile file; - final FileLocation start; - final FileLocation end; + /// The offset of the beginning of the span. + /// + /// [start] is lazily generated from this to avoid allocating unnecessary + /// objects. + final int _start; + + /// The offset of the end of the span. + /// + /// [end] is lazily generated from this to avoid allocating unnecessary + /// objects. + final int _end; + + FileLocation get start => new FileLocation._(file, _start); + FileLocation get end => new FileLocation._(file, _end); String get text => file.getText(start.offset, end.offset); - FileSpan._(this.file, this.start, this.end) { - if (end.offset < start.offset) { - throw new ArgumentError('End $end must come after start $start.'); + FileSpan._(this.file, this._start, this._end) { + if (_end < _start) { + throw new ArgumentError('End $_end must come after start $_start.'); } } @@ -222,8 +234,8 @@ class FileSpan extends SourceSpanMixin { " \"${other.sourceUrl}\" don't match."); } - var start = min(this.start, other.start); - var end = max(this.end, other.end); + var start = math.min(this._start, other._start); + var end = math.max(this._end, other._end); return new FileSpan._(file, start, end); } diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 66e5811ac..ae1bfcfa3 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,6 +1,6 @@ name: source_span -version: 1.0.0 +version: 1.0.1 author: Dart Team description: A library for identifying source spans and locations. homepage: http://www.dartlang.org From 5d7bc2c0124d8d2dfdd00f25b7f880751d7a20f2 Mon Sep 17 00:00:00 2001 From: "nweiz@google.com" Date: Fri, 7 Nov 2014 20:12:46 +0000 Subject: [PATCH 004/128] Fix source_span tests. R=rnystrom@google.com Review URL: https://codereview.chromium.org//712473002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/source_span@41614 260f80e4-7a28-3924-810f-c04153c831b5 --- pkgs/source_span/lib/src/file.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 5680733d4..14aa22627 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -207,6 +207,11 @@ class FileSpan extends SourceSpanMixin { FileSpan._(this.file, this._start, this._end) { if (_end < _start) { throw new ArgumentError('End $_end must come after start $_start.'); + } else if (_end > file.length) { + throw new RangeError("End $_end must not be greater than the number " + "of characters in the file, ${file.length}."); + } else if (_start < 0) { + throw new RangeError("Start may not be negative, was $_start."); } } From 9abb0961a9f1f091ad0ebe51814432922773ab14 Mon Sep 17 00:00:00 2001 From: "nweiz@google.com" Date: Fri, 21 Nov 2014 23:49:39 +0000 Subject: [PATCH 005/128] Avoid instantiating FileLocations where possible in source_span. R=rnystrom@google.com Review URL: https://codereview.chromium.org//754463002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/source_span@41921 260f80e4-7a28-3924-810f-c04153c831b5 --- pkgs/source_span/CHANGELOG.md | 7 ++++++ pkgs/source_span/lib/src/file.dart | 30 +++++++++++++++++++----- pkgs/source_span/lib/src/span_mixin.dart | 6 ++--- pkgs/source_span/pubspec.yaml | 2 +- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index e5190bcd9..f057e9b5c 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,10 @@ +# 1.0.2 + +* Avoid unintentionally allocating extra objects for internal `FileSpan` + operations. + +* Ensure that `SourceSpan.operator==` works on arbitrary `Object`s. + # 1.0.1 * Use a more compact internal representation for `FileSpan`. diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 14aa22627..ed5f6a837 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -199,10 +199,11 @@ class FileSpan extends SourceSpanMixin { /// objects. final int _end; + Uri get sourceUrl => file.url; + int get length => _end - _start; FileLocation get start => new FileLocation._(file, _start); FileLocation get end => new FileLocation._(file, _end); - - String get text => file.getText(start.offset, end.offset); + String get text => file.getText(_start, _end); FileSpan._(this.file, this._start, this._end) { if (_end < _start) { @@ -215,20 +216,37 @@ class FileSpan extends SourceSpanMixin { } } + int compareTo(SourceSpan other) { + if (other is! FileSpan) return super.compareTo(other); + + FileSpan otherFile = other; + var result = _start.compareTo(otherFile._start); + return result == 0 ? _end.compareTo(otherFile._end) : result; + } + SourceSpan union(SourceSpan other) { if (other is! FileSpan) return super.union(other); var span = expand(other); - var beginSpan = span.start == this.start ? this : other; - var endSpan = span.end == this.end ? this : other; + var beginSpan = span._start == _start ? this : other; + var endSpan = span._end == _end ? this : other; - if (beginSpan.end.compareTo(endSpan.start) < 0) { + if (beginSpan._end < endSpan._start) { throw new ArgumentError("Spans $this and $other are disjoint."); } return span; } + bool operator ==(other) { + if (other is! FileSpan) return super == other; + return _start == other._start && _end == other._end && + sourceUrl == other.sourceUrl; + } + + int get hashCode => _start.hashCode + 5 * _end.hashCode + + 7 * sourceUrl.hashCode; + /// Returns a new span that covers both [this] and [other]. /// /// Unlike [union], [other] may be disjoint from [this]. If it is, the text @@ -241,7 +259,7 @@ class FileSpan extends SourceSpanMixin { var start = math.min(this._start, other._start); var end = math.max(this._end, other._end); - return new FileSpan._(file, start, end); + return new FileSpan._(file, start, end); } String message(String message, {color}) { diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index 95a720aae..716e6e07b 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -21,8 +21,8 @@ abstract class SourceSpanMixin implements SourceSpan { int get length => end.offset - start.offset; int compareTo(SourceSpan other) { - int d = start.compareTo(other.start); - return d == 0 ? end.compareTo(other.end) : d; + var result = start.compareTo(other.start); + return result == 0 ? end.compareTo(other.end) : result; } SourceSpan union(SourceSpan other) { @@ -65,7 +65,7 @@ abstract class SourceSpanMixin implements SourceSpan { return buffer.toString(); } - bool operator ==(SourceSpan other) => + bool operator ==(other) => other is SourceSpan && start == other.start && end == other.end; int get hashCode => start.hashCode + (31 * end.hashCode); diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index ae1bfcfa3..5c166fc6f 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,6 +1,6 @@ name: source_span -version: 1.0.1 +version: 1.0.2 author: Dart Team description: A library for identifying source spans and locations. homepage: http://www.dartlang.org From 2b3e0406b4295c71b1213a90e14cb710f35eb82b Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 17 Dec 2014 16:27:37 -0800 Subject: [PATCH 006/128] Add gitignore, status, and codereview files. --- pkgs/source_span/.gitignore | 14 ++++++++++++++ pkgs/source_span/.status | 3 +++ pkgs/source_span/codereview.settings | 3 +++ 3 files changed, 20 insertions(+) create mode 100644 pkgs/source_span/.gitignore create mode 100644 pkgs/source_span/.status create mode 100644 pkgs/source_span/codereview.settings diff --git a/pkgs/source_span/.gitignore b/pkgs/source_span/.gitignore new file mode 100644 index 000000000..388eff0ba --- /dev/null +++ b/pkgs/source_span/.gitignore @@ -0,0 +1,14 @@ +# Don’t commit the following directories created by pub. +.buildlog +.pub/ +build/ +packages + +# Or the files created by dart2js. +*.dart.js +*.js_ +*.js.deps +*.js.map + +# Include when developing application packages. +pubspec.lock \ No newline at end of file diff --git a/pkgs/source_span/.status b/pkgs/source_span/.status new file mode 100644 index 000000000..e9f2b0049 --- /dev/null +++ b/pkgs/source_span/.status @@ -0,0 +1,3 @@ +# Copyright (c) 2014, 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. diff --git a/pkgs/source_span/codereview.settings b/pkgs/source_span/codereview.settings new file mode 100644 index 000000000..6cae815a0 --- /dev/null +++ b/pkgs/source_span/codereview.settings @@ -0,0 +1,3 @@ +CODE_REVIEW_SERVER: http://codereview.chromium.org/ +VIEW_VC: https://github.com/dart-lang/source_span/commit/ +CC_LIST: reviews@dartlang.org \ No newline at end of file From 98f02e21d5243a71eab869de9582f9af5b6cbaa7 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 17 Dec 2014 16:28:19 -0800 Subject: [PATCH 007/128] Update the pubspec's homepage link. --- pkgs/source_span/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 5c166fc6f..55ac89aa4 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -3,7 +3,7 @@ name: source_span version: 1.0.2 author: Dart Team description: A library for identifying source spans and locations. -homepage: http://www.dartlang.org +homepage: http://github.com/dart-lang/source_span dependencies: path: '>=1.2.0 <2.0.0' environment: From bda022d51dbbe5a615c7f432dd208c045e8f82fb Mon Sep 17 00:00:00 2001 From: Jacob Richman Date: Tue, 27 Jan 2015 15:30:49 -0800 Subject: [PATCH 008/128] Cleanup equality operator to accept any Object rather than just a SourceLocation. BUG= R=nweiz@google.com Review URL: https://codereview.chromium.org//881673002 --- pkgs/source_span/CHANGELOG.md | 5 +++++ pkgs/source_span/lib/src/location.dart | 5 +++-- pkgs/source_span/pubspec.yaml | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index f057e9b5c..195bcf8de 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.0.3 + +* Cleanup equality operator to accept any Object rather than just a + `SourceLocation`. + # 1.0.2 * Avoid unintentionally allocating extra objects for internal `FileSpan` diff --git a/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart index 41f251898..27057424b 100644 --- a/pkgs/source_span/lib/src/location.dart +++ b/pkgs/source_span/lib/src/location.dart @@ -77,8 +77,9 @@ class SourceLocation implements Comparable { return offset - other.offset; } - bool operator ==(SourceLocation other) => - sourceUrl == other.sourceUrl && offset == other.offset; + bool operator ==(other) => + other is SourceLocation && sourceUrl == other.sourceUrl && + offset == other.offset; int get hashCode => sourceUrl.hashCode + offset; diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 55ac89aa4..03b290b17 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,6 +1,6 @@ name: source_span -version: 1.0.2 +version: 1.0.3 author: Dart Team description: A library for identifying source spans and locations. homepage: http://github.com/dart-lang/source_span From 13fb954988cb960dc6d1d411e1da246a5b2d5848 Mon Sep 17 00:00:00 2001 From: Sigmund Cherem Date: Thu, 26 Mar 2015 14:55:28 -0700 Subject: [PATCH 009/128] Introduce span with line context R=nweiz@google.com Review URL: https://codereview.chromium.org//1028813002 --- pkgs/source_span/CHANGELOG.md | 5 ++ pkgs/source_span/lib/source_span.dart | 1 + pkgs/source_span/lib/src/file.dart | 46 +++--------- pkgs/source_span/lib/src/span_mixin.dart | 45 ++++++++++-- .../lib/src/span_with_context.dart | 38 ++++++++++ pkgs/source_span/pubspec.yaml | 5 +- pkgs/source_span/test/span_test.dart | 72 +++++++++++++++++-- pkgs/source_span/test/utils_test.dart | 1 - 8 files changed, 161 insertions(+), 52 deletions(-) create mode 100644 pkgs/source_span/lib/src/span_with_context.dart diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 195bcf8de..6ab52c8e1 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.1.0 + +* Added `SourceSpanWithContext`: a span that also includes the full line of text + that contains the span. + # 1.0.3 * Cleanup equality operator to accept any Object rather than just a diff --git a/pkgs/source_span/lib/source_span.dart b/pkgs/source_span/lib/source_span.dart index e9646b1fd..89b1650ea 100644 --- a/pkgs/source_span/lib/source_span.dart +++ b/pkgs/source_span/lib/source_span.dart @@ -9,3 +9,4 @@ export "src/location.dart"; export "src/span.dart"; export "src/span_exception.dart"; export "src/span_mixin.dart"; +export "src/span_with_context.dart"; diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index ed5f6a837..c7e58982f 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -13,6 +13,7 @@ import 'colors.dart' as colors; import 'location.dart'; import 'span.dart'; import 'span_mixin.dart'; +import 'span_with_context.dart'; import 'utils.dart'; // Constants to determine end-of-lines. @@ -183,7 +184,7 @@ class FileLocation extends SourceLocation { /// [FileSpan.union] will return a [FileSpan] if possible. /// /// A [FileSpan] can be created using [SourceFile.span]. -class FileSpan extends SourceSpanMixin { +class FileSpan extends SourceSpanMixin implements SourceSpanWithContext { /// The [file] that [this] belongs to. final SourceFile file; @@ -205,6 +206,12 @@ class FileSpan extends SourceSpanMixin { FileLocation get end => new FileLocation._(file, _end); String get text => file.getText(_start, _end); + String get context { + var line = start.line; + return file.getText(file.getOffset(line), + line == file.lines - 1 ? null : file.getOffset(line + 1)); + } + FileSpan._(this.file, this._start, this._end) { if (_end < _start) { throw new ArgumentError('End $_end must come after start $_start.'); @@ -261,41 +268,4 @@ class FileSpan extends SourceSpanMixin { var end = math.max(this._end, other._end); return new FileSpan._(file, start, end); } - - String message(String message, {color}) { - if (color == true) color = colors.RED; - if (color == false) color = null; - - var line = start.line; - var column = start.column; - - var buffer = new StringBuffer(); - buffer.write('line ${start.line + 1}, column ${start.column + 1}'); - if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}'); - buffer.write(': $message\n'); - - var textLine = file.getText(file.getOffset(line), - line == file.lines - 1 ? null : file.getOffset(line + 1)); - - column = math.min(column, textLine.length - 1); - var toColumn = - math.min(column + end.offset - start.offset, textLine.length); - - if (color != null) { - buffer.write(textLine.substring(0, column)); - buffer.write(color); - buffer.write(textLine.substring(column, toColumn)); - buffer.write(colors.NONE); - buffer.write(textLine.substring(toColumn)); - } else { - buffer.write(textLine); - } - if (!textLine.endsWith('\n')) buffer.write('\n'); - - buffer.write(' ' * column); - if (color != null) buffer.write(color); - buffer.write('^' * math.max(toColumn - column, 1)); - if (color != null) buffer.write(colors.NONE); - return buffer.toString(); - } } diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index 716e6e07b..a93723f10 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -4,10 +4,12 @@ library source_span.span_mixin; +import 'dart:math' as math; import 'package:path/path.dart' as p; import 'colors.dart' as colors; import 'span.dart'; +import 'span_with_context.dart'; import 'utils.dart'; /// A mixin for easily implementing [SourceSpan]. @@ -49,18 +51,49 @@ abstract class SourceSpanMixin implements SourceSpan { if (color == true) color = colors.RED; if (color == false) color = null; + var line = start.line; + var column = start.column; + var buffer = new StringBuffer(); - buffer.write('line ${start.line + 1}, column ${start.column + 1}'); + buffer.write('line ${line + 1}, column ${column + 1}'); if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}'); buffer.write(': $message'); - if (length == 0) return buffer.toString(); + if (length == 0 && this is! SourceSpanWithContext) return buffer.toString(); buffer.write("\n"); - var textLine = text.split("\n").first; + + var textLine; + if (this is SourceSpanWithContext) { + var context = (this as SourceSpanWithContext).context; + var textIndex = context.indexOf(text.split('\n').first); + var lineStart = context.lastIndexOf('\n', textIndex); + if (lineStart != -1) { + buffer.write(context.substring(0, lineStart + 1)); + context = context.substring(lineStart + 1); + } + var endIndex = context.indexOf('\n'); + textLine = endIndex == -1 ? context : context.substring(0, endIndex + 1); + column = math.min(column, textLine.length - 1); + } else { + textLine = text.split("\n").first; + column = 0; + } + + var toColumn = + math.min(column + end.offset - start.offset, textLine.length); + if (color != null) { + buffer.write(textLine.substring(0, column)); + buffer.write(color); + buffer.write(textLine.substring(column, toColumn)); + buffer.write(colors.NONE); + buffer.write(textLine.substring(toColumn)); + } else { + buffer.write(textLine); + } + if (!textLine.endsWith('\n')) buffer.write('\n'); + buffer.write(' ' * column); if (color != null) buffer.write(color); - buffer.write(textLine); - buffer.write("\n"); - buffer.write('^' * textLine.length); + buffer.write('^' * math.max(toColumn - column, 1)); if (color != null) buffer.write(colors.NONE); return buffer.toString(); } diff --git a/pkgs/source_span/lib/src/span_with_context.dart b/pkgs/source_span/lib/src/span_with_context.dart new file mode 100644 index 000000000..4d279de38 --- /dev/null +++ b/pkgs/source_span/lib/src/span_with_context.dart @@ -0,0 +1,38 @@ +// Copyright (c) 2014, 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. + +library source_span.span; + +import 'location.dart'; +import 'span.dart'; + +/// A class that describes a segment of source text with additional context. +class SourceSpanWithContext extends SourceSpanBase { + /// Text around the span, which includes the line containing this span. + final String context; + + /// Creates a new span from [start] to [end] (exclusive) containing [text], in + /// the given [context]. + /// + /// [start] and [end] must have the same source URL and [start] must come + /// before [end]. [text] must have a number of characters equal to the + /// distance between [start] and [end]. [context] must contain [text], and + /// [text] should start at `start.column` from the beginning of a line in + /// [context]. + SourceSpanWithContext( + SourceLocation start, SourceLocation end, String text, this.context) + : super(start, end, text) { + var index = context.indexOf(text); + if (index == -1) { + throw new ArgumentError( + 'The context line "$context" must contain "$text".'); + } + + var beginningOfLine = context.lastIndexOf('\n', index) + 1; + if (start.column != index - beginningOfLine) { + throw new ArgumentError('The span text "$text" must start at ' + 'column ${start.column + 1} in a line within "$context".'); + } + } +} diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 03b290b17..887c040ca 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,6 +1,5 @@ name: source_span - -version: 1.0.3 +version: 1.1.0 author: Dart Team description: A library for identifying source spans and locations. homepage: http://github.com/dart-lang/source_span @@ -9,4 +8,4 @@ dependencies: environment: sdk: '>=0.8.10+6 <2.0.0' dev_dependencies: - unittest: '>=0.9.0 <0.10.0' + unittest: '>=0.9.0 <0.12.0' diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart index c62753b1a..39b0b9433 100644 --- a/pkgs/source_span/test/span_test.dart +++ b/pkgs/source_span/test/span_test.dart @@ -36,6 +36,37 @@ main() { }); }); + group('for new SourceSpanWithContext()', () { + test('context must contain text', () { + var start = new SourceLocation(2); + var end = new SourceLocation(5); + expect(() => new SourceSpanWithContext( + start, end, "abc", "--axc--"), throwsArgumentError); + }); + + test('text starts at start.column in context', () { + var start = new SourceLocation(3); + var end = new SourceLocation(5); + expect(() => new SourceSpanWithContext( + start, end, "abc", "--abc--"), throwsArgumentError); + }); + + test('text starts at start.column of line in multi-line context', () { + var start = new SourceLocation(4, line: 55, column: 3); + var end = new SourceLocation(7, line: 55, column: 6); + expect(() => new SourceSpanWithContext( + start, end, "abc", "\n--abc--"), throwsArgumentError); + expect(() => new SourceSpanWithContext( + start, end, "abc", "\n----abc--"), throwsArgumentError); + expect(() => new SourceSpanWithContext( + start, end, "abc", "\n\n--abc--"), throwsArgumentError); + + // However, these are valid: + new SourceSpanWithContext(start, end, "abc", "\n---abc--"); + new SourceSpanWithContext(start, end, "abc", "\n\n---abc--"); + }); + }); + group('for union()', () { test('source URLs must match', () { var other = new SourceSpan( @@ -178,15 +209,48 @@ foo bar expect(span.message("oh no", color: true), equals(""" line 1, column 6 of foo.dart: oh no -${colors.RED}foo bar -^^^^^^^${colors.NONE}""")); +${colors.RED}foo bar${colors.NONE} +${colors.RED}^^^^^^^${colors.NONE}""")); }); test("uses the given color if it's passed", () { expect(span.message("oh no", color: colors.YELLOW), equals(""" line 1, column 6 of foo.dart: oh no -${colors.YELLOW}foo bar -^^^^^^^${colors.NONE}""")); +${colors.YELLOW}foo bar${colors.NONE} +${colors.YELLOW}^^^^^^^${colors.NONE}""")); + }); + }); + + group("message() with context", () { + var spanWithContext; + setUp(() { + spanWithContext = new SourceSpanWithContext( + new SourceLocation(5, sourceUrl: "foo.dart"), + new SourceLocation(12, sourceUrl: "foo.dart"), + "foo bar", + "-----foo bar-----"); + }); + + test("underlines under the right column", () { + expect(spanWithContext.message("oh no", color: colors.YELLOW), equals(""" +line 1, column 6 of foo.dart: oh no +-----${colors.YELLOW}foo bar${colors.NONE}----- + ${colors.YELLOW}^^^^^^^${colors.NONE}""")); + }); + + test("supports lines of preceeding context", () { + var span = new SourceSpanWithContext( + new SourceLocation(5, line: 3, column: 5, sourceUrl: "foo.dart"), + new SourceLocation(12, line: 3, column: 12, sourceUrl: "foo.dart"), + "foo bar", + "previous\nlines\n-----foo bar-----\nfollowing line\n"); + + expect(span.message("oh no", color: colors.YELLOW), equals(""" +line 4, column 6 of foo.dart: oh no +previous +lines +-----${colors.YELLOW}foo bar${colors.NONE}----- + ${colors.YELLOW}^^^^^^^${colors.NONE}""")); }); }); diff --git a/pkgs/source_span/test/utils_test.dart b/pkgs/source_span/test/utils_test.dart index 39211111e..a99884709 100644 --- a/pkgs/source_span/test/utils_test.dart +++ b/pkgs/source_span/test/utils_test.dart @@ -48,4 +48,3 @@ _linearSearch(list, predicate) { } return list.length; } - From 21cddeb0ee8f54a8e29558ea46f6448f7ec2a1e5 Mon Sep 17 00:00:00 2001 From: Sigmund Cherem Date: Thu, 26 Mar 2015 15:06:18 -0700 Subject: [PATCH 010/128] Fix library name (dartanalyzer was complaining in the bots) R=nweiz@google.com Review URL: https://codereview.chromium.org//1033083002 --- pkgs/source_span/lib/src/span_with_context.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/source_span/lib/src/span_with_context.dart b/pkgs/source_span/lib/src/span_with_context.dart index 4d279de38..edbb8b65f 100644 --- a/pkgs/source_span/lib/src/span_with_context.dart +++ b/pkgs/source_span/lib/src/span_with_context.dart @@ -2,7 +2,7 @@ // 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. -library source_span.span; +library source_span.span_with_context; import 'location.dart'; import 'span.dart'; From c7557077f5360675dff2774b4b03575dec2ba685 Mon Sep 17 00:00:00 2001 From: Sigmund Cherem Date: Fri, 27 Mar 2015 14:24:56 -0700 Subject: [PATCH 011/128] Fix FileSpan.context to include FileSpan.text. R=nweiz@google.com Review URL: https://codereview.chromium.org//1039603004 --- pkgs/source_span/CHANGELOG.md | 5 +++++ pkgs/source_span/lib/src/file.dart | 8 ++------ pkgs/source_span/pubspec.yaml | 2 +- pkgs/source_span/test/file_test.dart | 8 +++++++- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 6ab52c8e1..e749513fe 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.1.1 + +* Fixed `FileSpan`'s context to include the full span text, not just the first + line of it. + # 1.1.0 * Added `SourceSpanWithContext`: a span that also includes the full line of text diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index c7e58982f..4b4e026cb 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -205,12 +205,8 @@ class FileSpan extends SourceSpanMixin implements SourceSpanWithContext { FileLocation get start => new FileLocation._(file, _start); FileLocation get end => new FileLocation._(file, _end); String get text => file.getText(_start, _end); - - String get context { - var line = start.line; - return file.getText(file.getOffset(line), - line == file.lines - 1 ? null : file.getOffset(line + 1)); - } + String get context => file.getText(file.getOffset(start.line), + end.line == file.lines - 1 ? null : file.getOffset(end.line + 1)); FileSpan._(this.file, this._start, this._end) { if (_end < _start) { diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 887c040ca..73c266741 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.1.0 +version: 1.1.1 author: Dart Team description: A library for identifying source spans and locations. homepage: http://github.com/dart-lang/source_span diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index 114a17e44..c27c1f64f 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/test/file_test.dart @@ -253,6 +253,12 @@ zip zap zop""", url: "bar.dart").span(10, 11); expect(file.span(8, 15).text, equals("baz\nwhi")); }); + test("context contains the span's text", () { + var span = file.span(8, 15); + expect(span.context.contains(span.text), isTrue); + expect(span.context, equals('foo bar baz\nwhiz bang boom\n')); + }); + group("union()", () { var span; setUp(() { @@ -367,4 +373,4 @@ zip zap zop""", url: "bar.dart").span(10, 11); }); }); }); -} \ No newline at end of file +} From 0e4e3ffb57e7815fdd72f99ef382b2300e436f23 Mon Sep 17 00:00:00 2001 From: Sigmund Cherem Date: Tue, 31 Mar 2015 12:54:40 -0700 Subject: [PATCH 012/128] Support multiple occurrences of text in context R=nweiz@google.com Review URL: https://codereview.chromium.org//1041163005 --- pkgs/source_span/CHANGELOG.md | 5 +++ pkgs/source_span/lib/src/span_mixin.dart | 9 ++--- .../lib/src/span_with_context.dart | 7 ++-- pkgs/source_span/lib/src/utils.dart | 17 ++++++++ pkgs/source_span/pubspec.yaml | 2 +- pkgs/source_span/test/span_test.dart | 27 +++++++++++++ pkgs/source_span/test/utils_test.dart | 39 +++++++++++++++++++ 7 files changed, 96 insertions(+), 10 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index e749513fe..51b0feaa0 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.1.2 + +* Fixed validation in `SourceSpanWithContext` to allow multiple occurrences of + `text` within `context`. + # 1.1.1 * Fixed `FileSpan`'s context to include the full span text, not just the first diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index a93723f10..b4503facd 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -65,11 +65,10 @@ abstract class SourceSpanMixin implements SourceSpan { var textLine; if (this is SourceSpanWithContext) { var context = (this as SourceSpanWithContext).context; - var textIndex = context.indexOf(text.split('\n').first); - var lineStart = context.lastIndexOf('\n', textIndex); - if (lineStart != -1) { - buffer.write(context.substring(0, lineStart + 1)); - context = context.substring(lineStart + 1); + var lineStart = findLineStart(context, text, column); + if (lineStart != null && lineStart > 0) { + buffer.write(context.substring(0, lineStart)); + context = context.substring(lineStart); } var endIndex = context.indexOf('\n'); textLine = endIndex == -1 ? context : context.substring(0, endIndex + 1); diff --git a/pkgs/source_span/lib/src/span_with_context.dart b/pkgs/source_span/lib/src/span_with_context.dart index edbb8b65f..0012e3f3d 100644 --- a/pkgs/source_span/lib/src/span_with_context.dart +++ b/pkgs/source_span/lib/src/span_with_context.dart @@ -6,6 +6,7 @@ library source_span.span_with_context; import 'location.dart'; import 'span.dart'; +import 'utils.dart'; /// A class that describes a segment of source text with additional context. class SourceSpanWithContext extends SourceSpanBase { @@ -23,14 +24,12 @@ class SourceSpanWithContext extends SourceSpanBase { SourceSpanWithContext( SourceLocation start, SourceLocation end, String text, this.context) : super(start, end, text) { - var index = context.indexOf(text); - if (index == -1) { + if (!context.contains(text)) { throw new ArgumentError( 'The context line "$context" must contain "$text".'); } - var beginningOfLine = context.lastIndexOf('\n', index) + 1; - if (start.column != index - beginningOfLine) { + if (findLineStart(context, text, start.column) == null) { throw new ArgumentError('The span text "$text" must start at ' 'column ${start.column + 1} in a line within "$context".'); } diff --git a/pkgs/source_span/lib/src/utils.dart b/pkgs/source_span/lib/src/utils.dart index 4a8eb551e..2d3386542 100644 --- a/pkgs/source_span/lib/src/utils.dart +++ b/pkgs/source_span/lib/src/utils.dart @@ -37,3 +37,20 @@ int binarySearch(List list, bool matches(item)) { return max; } +/// Finds a line in [context] containing [text] at the specified [column]. +/// +/// Returns the index in [context] where that line begins, or null if none +/// exists. +int findLineStart(String context, String text, int column) { + var isEmpty = text == ''; + var index = context.indexOf(text); + while (index != -1) { + var lineStart = context.lastIndexOf('\n', index) + 1; + var textColumn = index - lineStart; + if (column == textColumn || (isEmpty && column == textColumn + 1)) { + return lineStart; + } + index = context.indexOf(text, index + 1); + } + return null; +} diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 73c266741..16eee7cca 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.1.1 +version: 1.1.2 author: Dart Team description: A library for identifying source spans and locations. homepage: http://github.com/dart-lang/source_span diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart index 39b0b9433..2657f5ffd 100644 --- a/pkgs/source_span/test/span_test.dart +++ b/pkgs/source_span/test/span_test.dart @@ -65,6 +65,21 @@ main() { new SourceSpanWithContext(start, end, "abc", "\n---abc--"); new SourceSpanWithContext(start, end, "abc", "\n\n---abc--"); }); + + test('text can occur multiple times in context', () { + var start1 = new SourceLocation(4, line: 55, column: 2); + var end1 = new SourceLocation(7, line: 55, column: 5); + var start2 = new SourceLocation(4, line: 55, column: 8); + var end2 = new SourceLocation(7, line: 55, column: 11); + new SourceSpanWithContext(start1, end1, "abc", "--abc---abc--\n"); + new SourceSpanWithContext(start1, end1, "abc", "--abc--abc--\n"); + new SourceSpanWithContext(start2, end2, "abc", "--abc---abc--\n"); + new SourceSpanWithContext(start2, end2, "abc", "---abc--abc--\n"); + expect(() => new SourceSpanWithContext( + start1, end1, "abc", "---abc--abc--\n"), throwsArgumentError); + expect(() => new SourceSpanWithContext( + start2, end2, "abc", "--abc--abc--\n"), throwsArgumentError); + }); }); group('for union()', () { @@ -238,6 +253,18 @@ line 1, column 6 of foo.dart: oh no ${colors.YELLOW}^^^^^^^${colors.NONE}""")); }); + test("underlines correctly when text appears twice", () { + var span = new SourceSpanWithContext( + new SourceLocation(9, column: 9, sourceUrl: "foo.dart"), + new SourceLocation(12, column: 12, sourceUrl: "foo.dart"), + "foo", + "-----foo foo-----"); + expect(span.message("oh no", color: colors.YELLOW), equals(""" +line 1, column 10 of foo.dart: oh no +-----foo ${colors.YELLOW}foo${colors.NONE}----- + ${colors.YELLOW}^^^${colors.NONE}""")); + }); + test("supports lines of preceeding context", () { var span = new SourceSpanWithContext( new SourceLocation(5, line: 3, column: 5, sourceUrl: "foo.dart"), diff --git a/pkgs/source_span/test/utils_test.dart b/pkgs/source_span/test/utils_test.dart index a99884709..74975c35b 100644 --- a/pkgs/source_span/test/utils_test.dart +++ b/pkgs/source_span/test/utils_test.dart @@ -39,6 +39,45 @@ 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); + 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); + expect(index, 5); + expect(context[index], '5'); + }); + + test('column at the end of the file for empty text', () { + var context = '0\n2\n45\n'; + var index = findLineStart(context, '', 2); + expect(index, 4); + expect(context[index], '4'); + + context = '0\n2\n45'; + index = findLineStart(context, '', 2); + expect(index, 4); + }); + + test('found on the first line', () { + var context = '0\n2\n45\n'; + var index = findLineStart(context, '0', 0); + expect(index, 0); + }); + + test('not found', () { + var context = '0\n2\n45\n'; + var index = findLineStart(context, '0', 1); + expect(index, isNull); + }); + }); } _linearSearch(list, predicate) { From 183673110fc416d39e26d26f0058c14a29174742 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 16 Jul 2015 13:39:56 -0700 Subject: [PATCH 013/128] Upgrade to the new test runner. R=sigmund@google.com Review URL: https://codereview.chromium.org//1240033002 . --- pkgs/source_span/.gitignore | 1 + pkgs/source_span/.status | 3 --- pkgs/source_span/.test_config | 3 +++ pkgs/source_span/pubspec.yaml | 4 ++-- pkgs/source_span/test/file_message_test.dart | 2 +- pkgs/source_span/test/file_test.dart | 2 +- pkgs/source_span/test/location_test.dart | 2 +- pkgs/source_span/test/span_test.dart | 2 +- pkgs/source_span/test/utils_test.dart | 2 +- 9 files changed, 11 insertions(+), 10 deletions(-) delete mode 100644 pkgs/source_span/.status create mode 100644 pkgs/source_span/.test_config diff --git a/pkgs/source_span/.gitignore b/pkgs/source_span/.gitignore index 388eff0ba..7dbf0350d 100644 --- a/pkgs/source_span/.gitignore +++ b/pkgs/source_span/.gitignore @@ -3,6 +3,7 @@ .pub/ build/ packages +.packages # Or the files created by dart2js. *.dart.js diff --git a/pkgs/source_span/.status b/pkgs/source_span/.status deleted file mode 100644 index e9f2b0049..000000000 --- a/pkgs/source_span/.status +++ /dev/null @@ -1,3 +0,0 @@ -# Copyright (c) 2014, 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. diff --git a/pkgs/source_span/.test_config b/pkgs/source_span/.test_config new file mode 100644 index 000000000..412fc5c5c --- /dev/null +++ b/pkgs/source_span/.test_config @@ -0,0 +1,3 @@ +{ + "test_package": true +} \ No newline at end of file diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 16eee7cca..8f69deb3c 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.1.2 +version: 1.1.3-dev author: Dart Team description: A library for identifying source spans and locations. homepage: http://github.com/dart-lang/source_span @@ -8,4 +8,4 @@ dependencies: environment: sdk: '>=0.8.10+6 <2.0.0' dev_dependencies: - unittest: '>=0.9.0 <0.12.0' + test: '>=0.12.0 <0.13.0' diff --git a/pkgs/source_span/test/file_message_test.dart b/pkgs/source_span/test/file_message_test.dart index 18b34e71b..5935c5882 100644 --- a/pkgs/source_span/test/file_message_test.dart +++ b/pkgs/source_span/test/file_message_test.dart @@ -2,7 +2,7 @@ // 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:unittest/unittest.dart'; +import 'package:test/test.dart'; import 'package:source_span/source_span.dart'; import 'package:source_span/src/colors.dart' as colors; diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index c27c1f64f..54bc3d34e 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/test/file_test.dart @@ -2,7 +2,7 @@ // 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:unittest/unittest.dart'; +import 'package:test/test.dart'; import 'package:source_span/source_span.dart'; main() { diff --git a/pkgs/source_span/test/location_test.dart b/pkgs/source_span/test/location_test.dart index 1eedec43a..dcd497a9f 100644 --- a/pkgs/source_span/test/location_test.dart +++ b/pkgs/source_span/test/location_test.dart @@ -2,7 +2,7 @@ // 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:unittest/unittest.dart'; +import 'package:test/test.dart'; import 'package:source_span/source_span.dart'; main() { diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart index 2657f5ffd..113848acf 100644 --- a/pkgs/source_span/test/span_test.dart +++ b/pkgs/source_span/test/span_test.dart @@ -2,7 +2,7 @@ // 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:unittest/unittest.dart'; +import 'package:test/test.dart'; import 'package:source_span/source_span.dart'; import 'package:source_span/src/colors.dart' as colors; diff --git a/pkgs/source_span/test/utils_test.dart b/pkgs/source_span/test/utils_test.dart index 74975c35b..3b6238b55 100644 --- a/pkgs/source_span/test/utils_test.dart +++ b/pkgs/source_span/test/utils_test.dart @@ -2,7 +2,7 @@ // 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:unittest/unittest.dart'; +import 'package:test/test.dart'; import 'package:source_span/src/utils.dart'; main() { From e6834f345812b5d0f2e8a4e77095cf8a73bdc96f Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 18 Aug 2015 15:01:35 -0700 Subject: [PATCH 014/128] Support external implementations of FileSpan. Previously, several FileSpan methods assumed that all FileSpans were implementations of this package's FileSpan class. However, this may not always be true. It can be useful to create FileSpans without first creating a SourceFile when efficient representations of line/column information are already available, and the user doesn't want to eagerly do the parsing necessary to create a full SourceFile. This also fixes an inconsistency between FileSpan.== and FileSpan.hashCode. R=sigmund@google.com Review URL: https://codereview.chromium.org//1298093002 . --- pkgs/source_span/CHANGELOG.md | 7 ++++ pkgs/source_span/lib/src/file.dart | 51 ++++++++++++++++++++---------- pkgs/source_span/pubspec.yaml | 2 +- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 51b0feaa0..8ca9e5cf0 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,10 @@ +# 1.1.3 + +* `FileSpan.compareTo`, `FileSpan.==`, `FileSpan.union`, and `FileSpan.expand` + no longer throw exceptions for external implementations of `FileSpan`. + +* `FileSpan.hashCode` now fully agrees with `FileSpan.==`. + # 1.1.2 * Fixed validation in `SourceSpanWithContext` to allow multiple occurrences of diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 4b4e026cb..c180929f7 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -7,9 +7,6 @@ library source_span.file; import 'dart:math' as math; import 'dart:typed_data'; -import 'package:path/path.dart' as p; - -import 'colors.dart' as colors; import 'location.dart'; import 'span.dart'; import 'span_mixin.dart'; @@ -74,7 +71,7 @@ class SourceFile { /// If [end] isn't passed, it defaults to the end of the file. FileSpan span(int start, [int end]) { if (end == null) end = length - 1; - return new FileSpan._(this, start, end); + return new _FileSpan(this, start, end); } /// Returns a location in [this] at [offset]. @@ -173,7 +170,7 @@ class FileLocation extends SourceLocation { } } - FileSpan pointSpan() => new FileSpan._(file, offset, offset); + FileSpan pointSpan() => new _FileSpan(file, offset, offset); } /// A [SourceSpan] within a [SourceFile]. @@ -184,8 +181,23 @@ class FileLocation extends SourceLocation { /// [FileSpan.union] will return a [FileSpan] if possible. /// /// A [FileSpan] can be created using [SourceFile.span]. -class FileSpan extends SourceSpanMixin implements SourceSpanWithContext { +abstract class FileSpan implements SourceSpanWithContext { /// The [file] that [this] belongs to. + SourceFile get file; + + /// Returns a new span that covers both [this] and [other]. + /// + /// 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); +} + +/// The implementation of [FileSpan]. +/// +/// This is split into a separate class so that `is _FileSpan` checks can be run +/// 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 { final SourceFile file; /// The offset of the beginning of the span. @@ -208,7 +220,7 @@ class FileSpan extends SourceSpanMixin implements SourceSpanWithContext { String get context => file.getText(file.getOffset(start.line), end.line == file.lines - 1 ? null : file.getOffset(end.line + 1)); - FileSpan._(this.file, this._start, this._end) { + _FileSpan(this.file, this._start, this._end) { if (_end < _start) { throw new ArgumentError('End $_end must come after start $_start.'); } else if (_end > file.length) { @@ -220,9 +232,9 @@ class FileSpan extends SourceSpanMixin implements SourceSpanWithContext { } int compareTo(SourceSpan other) { - if (other is! FileSpan) return super.compareTo(other); + if (other is! _FileSpan) return super.compareTo(other); - FileSpan otherFile = other; + _FileSpan otherFile = other; var result = _start.compareTo(otherFile._start); return result == 0 ? _end.compareTo(otherFile._end) : result; } @@ -230,7 +242,7 @@ class FileSpan extends SourceSpanMixin implements SourceSpanWithContext { SourceSpan union(SourceSpan other) { if (other is! FileSpan) return super.union(other); - var span = expand(other); + _FileSpan span = expand(other); var beginSpan = span._start == _start ? this : other; var endSpan = span._end == _end ? this : other; @@ -243,13 +255,14 @@ class FileSpan extends SourceSpanMixin implements SourceSpanWithContext { bool operator ==(other) { if (other is! FileSpan) return super == other; + if (other is! _FileSpan) { + return super == other && sourceUrl == other.sourceUrl; + } + return _start == other._start && _end == other._end && sourceUrl == other.sourceUrl; } - int get hashCode => _start.hashCode + 5 * _end.hashCode + - 7 * sourceUrl.hashCode; - /// Returns a new span that covers both [this] and [other]. /// /// Unlike [union], [other] may be disjoint from [this]. If it is, the text @@ -260,8 +273,14 @@ class FileSpan extends SourceSpanMixin implements SourceSpanWithContext { " \"${other.sourceUrl}\" don't match."); } - var start = math.min(this._start, other._start); - var end = math.max(this._end, other._end); - return new FileSpan._(file, start, end); + if (other is _FileSpan) { + var start = math.min(this._start, other._start); + var end = math.max(this._end, other._end); + return new _FileSpan(file, start, end); + } else { + var start = math.min(this._start, other.start.offset); + var end = math.max(this._end, other.end.offset); + return new _FileSpan(file, start, end); + } } } diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 8f69deb3c..daee3f61c 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.1.3-dev +version: 1.1.3 author: Dart Team description: A library for identifying source spans and locations. homepage: http://github.com/dart-lang/source_span From 433b99839a2fc64644d2d3e17a16afad1662a43c Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Thu, 27 Aug 2015 18:14:01 -0700 Subject: [PATCH 015/128] Eliminate dart2js warning about overriding `==`, but not `hashCode`. Closes dart-lang/source_spandart-lang/source_span#5 R=nweiz@google.com Review URL: https://codereview.chromium.org//1315423002 . --- pkgs/source_span/CHANGELOG.md | 4 ++++ pkgs/source_span/lib/src/file.dart | 3 +++ pkgs/source_span/pubspec.yaml | 4 ++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 8ca9e5cf0..5f87aeeaf 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.1.4 + +* Eliminated dart2js warning about overriding `==`, but not `hashCode`. + # 1.1.3 * `FileSpan.compareTo`, `FileSpan.==`, `FileSpan.union`, and `FileSpan.expand` diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index c180929f7..aee3d7831 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -263,6 +263,9 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { sourceUrl == other.sourceUrl; } + // Eliminates dart2js warning about overriding `==`, but not `hashCode` + int get hashCode => super.hashCode; + /// Returns a new span that covers both [this] and [other]. /// /// Unlike [union], [other] may be disjoint from [this]. If it is, the text diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index daee3f61c..3da9c289a 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,8 +1,8 @@ name: source_span -version: 1.1.3 +version: 1.1.4 author: Dart Team description: A library for identifying source spans and locations. -homepage: http://github.com/dart-lang/source_span +homepage: https://github.com/dart-lang/source_span dependencies: path: '>=1.2.0 <2.0.0' environment: From b1e9d7546144392632dab050dded563267e642d4 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 1 Sep 2015 15:45:23 -0700 Subject: [PATCH 016/128] Make the package strong-mode clean. This caught a bug in which we were calling _FileSpan._start and _FileSpan._end on a span we couldn't guarantee to be a _FileSpan. R=sigmund@google.com Review URL: https://codereview.chromium.org//1328583002 . --- pkgs/source_span/CHANGELOG.md | 5 +++++ pkgs/source_span/lib/src/file.dart | 13 +++++++++---- pkgs/source_span/pubspec.yaml | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 5f87aeeaf..10d94f6ab 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.1.5 + +* Fixed another case in which `FileSpan.union` could throw an exception for + external implementations of `FileSpan`. + # 1.1.4 * Eliminated dart2js warning about overriding `==`, but not `hashCode`. diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index aee3d7831..e5bc53c81 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -242,12 +242,17 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { SourceSpan union(SourceSpan other) { if (other is! FileSpan) return super.union(other); + _FileSpan span = expand(other); - var beginSpan = span._start == _start ? this : other; - var endSpan = span._end == _end ? this : other; - if (beginSpan._end < endSpan._start) { - throw new ArgumentError("Spans $this and $other are disjoint."); + if (other is _FileSpan) { + if (this._start > other._end || other._start > this._end) { + throw new ArgumentError("Spans $this and $other are disjoint."); + } + } else { + if (this._start > other.end.offset || other.start.offset > this._end) { + throw new ArgumentError("Spans $this and $other are disjoint."); + } } return span; diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 3da9c289a..2bfbe4e2f 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.1.4 +version: 1.1.5 author: Dart Team description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span From 445aa0ec6c4d0c95e79b398451659b46b4fd448a Mon Sep 17 00:00:00 2001 From: Robert Nystrom Date: Tue, 1 Sep 2015 17:37:16 -0700 Subject: [PATCH 017/128] Optimize successive calls SourceFile.getLine(). R=nweiz@google.com Review URL: https://codereview.chromium.org//1319303004 . --- pkgs/source_span/CHANGELOG.md | 1 + pkgs/source_span/lib/src/file.dart | 62 +++++++++++++++++++++++++- pkgs/source_span/lib/src/location.dart | 6 +-- pkgs/source_span/lib/src/utils.dart | 23 ---------- pkgs/source_span/test/utils_test.dart | 34 -------------- 5 files changed, 64 insertions(+), 62 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 10d94f6ab..caf8af5e5 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -2,6 +2,7 @@ * Fixed another case in which `FileSpan.union` could throw an exception for external implementations of `FileSpan`. +* Optimize `getLine()` in `SourceFile` when repeatedly called. # 1.1.4 diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index e5bc53c81..c2b97e782 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -11,7 +11,6 @@ import 'location.dart'; import 'span.dart'; import 'span_mixin.dart'; import 'span_with_context.dart'; -import 'utils.dart'; // Constants to determine end-of-lines. const int _LF = 10; @@ -43,6 +42,14 @@ class SourceFile { /// The number of lines in the file. int get lines => _lineStarts.length; + /// The line that the offset fell on the last time [getLine] was called. + /// + /// In many cases, sequential calls to getLine() are for nearby, usually + /// increasing offsets. In that case, we can find the line for an offset + /// quickly by first checking to see if the offset is on the same line as the + /// previous result. + int _cachedLine; + /// Creates a new source file from [text]. /// /// [url] may be either a [String], a [Uri], or `null`. @@ -85,7 +92,58 @@ class SourceFile { throw new RangeError("Offset $offset must not be greater than the number " "of characters in the file, $length."); } - return binarySearch(_lineStarts, (o) => o > offset) - 1; + + if (offset < _lineStarts.first) return -1; + if (offset >= _lineStarts.last) return _lineStarts.length - 1; + + if (_isNearCachedLine(offset)) return _cachedLine; + + _cachedLine = _binarySearch(offset) - 1; + return _cachedLine; + } + + /// Returns `true` if [offset] is near [_cachedLine]. + /// + /// Checks on [_cachedLine] and the next line. If it's on the next line, it + /// updates [_cachedLine] to point to that. + bool _isNearCachedLine(int offset) { + if (_cachedLine == null) return false; + + // See if it's before the cached line. + if (offset < _lineStarts[_cachedLine]) return false; + + // See if it's on the cached line. + if (_cachedLine >= _lineStarts.length - 1 || + offset < _lineStarts[_cachedLine + 1]) { + return true; + } + + // See if it's on the next line. + if (_cachedLine >= _lineStarts.length - 2 || + offset < _lineStarts[_cachedLine + 2]) { + _cachedLine++; + return true; + } + + return false; + } + + /// Binary search through [_lineStarts] to find the line containing [offset]. + /// + /// Returns the index of the line in [_lineStarts]. + int _binarySearch(int offset) { + int min = 0; + int max = _lineStarts.length - 1; + while (min < max) { + var half = min + ((max - min) ~/ 2); + if (_lineStarts[half] > offset) { + max = half; + } else { + min = half + 1; + } + } + + return max; } /// Gets the 0-based column corresponding to [offset]. diff --git a/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart index 27057424b..42e2b7dd7 100644 --- a/pkgs/source_span/lib/src/location.dart +++ b/pkgs/source_span/lib/src/location.dart @@ -44,11 +44,11 @@ class SourceLocation implements Comparable { line = line == null ? 0 : line, column = column == null ? offset : column { if (this.offset < 0) { - throw new RangeError("Offset may not be negative, was $offset."); + throw new RangeError("Offset may not be negative, was ${this.offset}."); } else if (this.line < 0) { - throw new RangeError("Line may not be negative, was $line."); + throw new RangeError("Line may not be negative, was ${this.line}."); } else if (this.column < 0) { - throw new RangeError("Column may not be negative, was $column."); + throw new RangeError("Column may not be negative, was ${this.column}."); } } diff --git a/pkgs/source_span/lib/src/utils.dart b/pkgs/source_span/lib/src/utils.dart index 2d3386542..fa0895784 100644 --- a/pkgs/source_span/lib/src/utils.dart +++ b/pkgs/source_span/lib/src/utils.dart @@ -14,29 +14,6 @@ Comparable min(Comparable obj1, Comparable obj2) => Comparable max(Comparable obj1, Comparable obj2) => obj1.compareTo(obj2) > 0 ? obj1 : obj2; -/// Find the first entry in a sorted [list] that matches a monotonic predicate. -/// -/// Given a result `n`, that all items before `n` will not match, `n` matches, -/// and all items after `n` match too. The result is -1 when there are no -/// items, 0 when all items match, and list.length when none does. -int binarySearch(List list, bool matches(item)) { - if (list.length == 0) return -1; - if (matches(list.first)) return 0; - if (!matches(list.last)) return list.length; - - int min = 0; - int max = list.length - 1; - while (min < max) { - var half = min + ((max - min) ~/ 2); - if (matches(list[half])) { - max = half; - } else { - min = half + 1; - } - } - return max; -} - /// Finds a line in [context] containing [text] at the specified [column]. /// /// Returns the index in [context] where that line begins, or null if none diff --git a/pkgs/source_span/test/utils_test.dart b/pkgs/source_span/test/utils_test.dart index 3b6238b55..5d973f58a 100644 --- a/pkgs/source_span/test/utils_test.dart +++ b/pkgs/source_span/test/utils_test.dart @@ -6,40 +6,6 @@ import 'package:test/test.dart'; import 'package:source_span/src/utils.dart'; main() { - group('binary search', () { - test('empty', () { - expect(binarySearch([], (x) => true), -1); - }); - - test('single element', () { - expect(binarySearch([1], (x) => true), 0); - expect(binarySearch([1], (x) => false), 1); - }); - - test('no matches', () { - var list = [1, 2, 3, 4, 5, 6, 7]; - expect(binarySearch(list, (x) => false), list.length); - }); - - test('all match', () { - var list = [1, 2, 3, 4, 5, 6, 7]; - expect(binarySearch(list, (x) => true), 0); - }); - - test('compare with linear search', () { - for (int size = 0; size < 100; size++) { - var list = []; - for (int i = 0; i < size; i++) { - list.add(i); - } - for (int pos = 0; pos <= size; pos++) { - expect(binarySearch(list, (x) => x >= pos), - _linearSearch(list, (x) => x >= pos)); - } - } - }); - }); - group('find line start', () { test('skip entries in wrong column', () { var context = '0_bb\n1_bbb\n2b____\n3bbb\n'; From b7846b03244d6121735badb9009158cc4aa642cd Mon Sep 17 00:00:00 2001 From: Robert Nystrom Date: Tue, 1 Sep 2015 17:42:23 -0700 Subject: [PATCH 018/128] Bump version. R=nweiz@google.com Review URL: https://codereview.chromium.org//1312623006 . --- pkgs/source_span/CHANGELOG.md | 5 ++++- pkgs/source_span/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index caf8af5e5..59923d511 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,8 +1,11 @@ +# 1.1.6 + +* Optimize `getLine()` in `SourceFile` when repeatedly called. + # 1.1.5 * Fixed another case in which `FileSpan.union` could throw an exception for external implementations of `FileSpan`. -* Optimize `getLine()` in `SourceFile` when repeatedly called. # 1.1.4 diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 2bfbe4e2f..a084bdf52 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.1.5 +version: 1.1.6 author: Dart Team description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span From 7d0ff863609f07a8bf994c948ec0803c05aaa6ac Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 2 Sep 2015 11:44:06 -0700 Subject: [PATCH 019/128] Fix a performance bug with FileLocation. The bug was actually located in SourceLocation. The constructor accesses this.line and `this.column` in preference to the arguments it was passed, which was fine for normal SourceLocations but for FileLocations caused two binary searches to be performed every time a location was instantiated. R=rnystrom@google.com Review URL: https://codereview.chromium.org//1328613002 . --- pkgs/source_span/CHANGELOG.md | 4 ++++ pkgs/source_span/lib/src/location.dart | 12 ++++++------ pkgs/source_span/pubspec.yaml | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 59923d511..6bd18f170 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.2.0 + +* Dramatically improve the performance of `FileLocation`. + # 1.1.6 * Optimize `getLine()` in `SourceFile` when repeatedly called. diff --git a/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart index 42e2b7dd7..024c6e278 100644 --- a/pkgs/source_span/lib/src/location.dart +++ b/pkgs/source_span/lib/src/location.dart @@ -43,12 +43,12 @@ class SourceLocation implements Comparable { offset = offset, line = line == null ? 0 : line, column = column == null ? offset : column { - if (this.offset < 0) { - throw new RangeError("Offset may not be negative, was ${this.offset}."); - } else if (this.line < 0) { - throw new RangeError("Line may not be negative, was ${this.line}."); - } else if (this.column < 0) { - throw new RangeError("Column may not be negative, was ${this.column}."); + if (offset < 0) { + throw new RangeError("Offset may not be negative, was $offset."); + } else if (line != null && line < 0) { + throw new RangeError("Line may not be negative, was $line."); + } else if (column != null && column < 0) { + throw new RangeError("Column may not be negative, was $column."); } } diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index a084bdf52..7ffbc6448 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.1.6 +version: 1.2.0-dev author: Dart Team description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span From e61c7fd3bf510660bc4d7f129d3ad7f1536ea3e8 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 2 Sep 2015 13:32:02 -0700 Subject: [PATCH 020/128] Add SourceLocationMixin and SourceLocationBase. This allows FileLocation to avoid extending SourceLocation at all, which avoids unused line, column, and sourceUrl fields. This produces a speed improvement of approximately 5% in the YAML parser, and will likely do more in code that uses locations more heavily relative to spans. R=rnystrom@google.com Review URL: https://codereview.chromium.org//1307123004 . --- pkgs/source_span/CHANGELOG.md | 4 ++ pkgs/source_span/lib/source_span.dart | 1 + pkgs/source_span/lib/src/file.dart | 11 +++-- pkgs/source_span/lib/src/location.dart | 15 +++++- pkgs/source_span/lib/src/location_mixin.dart | 51 ++++++++++++++++++++ pkgs/source_span/pubspec.yaml | 2 +- 6 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 pkgs/source_span/lib/src/location_mixin.dart diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 6bd18f170..ab13bda83 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,5 +1,9 @@ # 1.2.0 +* **Deprecated:** Extending `SourceLocation` directly is deprecated. Instead, + extend the new `SourceLocationBase` class or mix in the new + `SourceLocationMixin` mixin. + * Dramatically improve the performance of `FileLocation`. # 1.1.6 diff --git a/pkgs/source_span/lib/source_span.dart b/pkgs/source_span/lib/source_span.dart index 89b1650ea..9666dc296 100644 --- a/pkgs/source_span/lib/source_span.dart +++ b/pkgs/source_span/lib/source_span.dart @@ -6,6 +6,7 @@ library source_span; export "src/file.dart"; export "src/location.dart"; +export "src/location_mixin.dart"; export "src/span.dart"; export "src/span_exception.dart"; export "src/span_mixin.dart"; diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index c2b97e782..95fa92ca3 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -8,6 +8,7 @@ import 'dart:math' as math; import 'dart:typed_data'; import 'location.dart'; +import 'location_mixin.dart'; import 'span.dart'; import 'span_mixin.dart'; import 'span_with_context.dart'; @@ -212,17 +213,19 @@ class SourceFile { /// and column values based on its offset and the contents of [file]. /// /// A [FileLocation] can be created using [SourceFile.location]. -class FileLocation extends SourceLocation { +class FileLocation extends SourceLocationMixin implements SourceLocation { /// The [file] that [this] belongs to. final SourceFile file; + final int offset; Uri get sourceUrl => file.url; int get line => file.getLine(offset); int get column => file.getColumn(offset); - FileLocation._(this.file, int offset) - : super(offset) { - if (offset > file.length) { + FileLocation._(this.file, this.offset) { + if (offset < 0) { + throw new RangeError("Offset may not be negative, was $offset."); + } else if (offset > file.length) { throw new RangeError("Offset $offset must not be greater than the number " "of characters in the file, ${file.length}."); } diff --git a/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart index 024c6e278..afb37c768 100644 --- a/pkgs/source_span/lib/src/location.dart +++ b/pkgs/source_span/lib/src/location.dart @@ -6,7 +6,13 @@ library source_span.location; import 'span.dart'; -// A class that describes a single location within a source file. +// TODO(nweiz): Use SourceLocationMixin once we decide to cut a release with +// breaking changes. See SourceLocationMixin for details. + +/// A class that describes a single location within a source file. +/// +/// This class should not be extended. Instead, [SourceLocationBase] should be +/// extended instead. class SourceLocation implements Comparable { /// URL of the source containing this location. /// @@ -85,3 +91,10 @@ class SourceLocation implements Comparable { String toString() => '<$runtimeType: $offset $toolString>'; } + +/// A base class for source locations with [offset], [line], and [column] known +/// at construction time. +class SourceLocationBase extends SourceLocation { + SourceLocationBase(int offset, {sourceUrl, int line, int column}) + : super(offset, sourceUrl: sourceUrl, line: line, column: column); +} diff --git a/pkgs/source_span/lib/src/location_mixin.dart b/pkgs/source_span/lib/src/location_mixin.dart new file mode 100644 index 000000000..5aa0de5ce --- /dev/null +++ b/pkgs/source_span/lib/src/location_mixin.dart @@ -0,0 +1,51 @@ +// Copyright (c) 2015, 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. + +library source_span.location_mixin; + +import 'location.dart'; +import 'span.dart'; + +// Note: this class duplicates a lot of functionality of [SourceLocation]. This +// is because in order for SourceLocation to use SourceLocationMixin, +// SourceLocationMixin couldn't implement SourceLocation. In SourceSpan we +// handle this by making the class itself non-extensible, but that would be a +// breaking change for SourceLocation. So until we want to endure the pain of +// cutting a release with breaking changes, we duplicate the code here. + +/// A mixin for easily implementing [SourceLocation]. +abstract class SourceLocationMixin implements SourceLocation { + String get toolString { + var source = sourceUrl == null ? 'unknown source' : sourceUrl; + return '$source:${line + 1}:${column + 1}'; + } + + int distance(SourceLocation other) { + if (sourceUrl != other.sourceUrl) { + throw new ArgumentError("Source URLs \"${sourceUrl}\" and " + "\"${other.sourceUrl}\" don't match."); + } + return (offset - other.offset).abs(); + } + + SourceSpan pointSpan() => new SourceSpan(this, this, ""); + + int compareTo(SourceLocation other) { + if (sourceUrl != other.sourceUrl) { + throw new ArgumentError("Source URLs \"${sourceUrl}\" and " + "\"${other.sourceUrl}\" don't match."); + } + return offset - other.offset; + } + + bool operator ==(other) => + other is SourceLocation && + sourceUrl == other.sourceUrl && + offset == other.offset; + + int get hashCode => sourceUrl.hashCode + offset; + + String toString() => '<$runtimeType: $offset $toolString>'; +} + diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 7ffbc6448..25de799d7 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.2.0-dev +version: 1.2.0 author: Dart Team description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span From 57c51dd58735056e73fa5615d61a7946949fb862 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 30 Sep 2015 13:37:33 -0700 Subject: [PATCH 021/128] Fix the typing of FileSpan.{start,end}. R=kevmoo@google.com Review URL: https://codereview.chromium.org//1376433003 . --- pkgs/source_span/CHANGELOG.md | 5 +++++ pkgs/source_span/lib/src/file.dart | 3 +++ pkgs/source_span/pubspec.yaml | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index ab13bda83..ce7198068 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.2.1 + +* Fix the declared type of `FileSpan.start` and `FileSpan.end`. In 1.2.0 these + were mistakenly changed from `FileLocation` to `SourceLocation`. + # 1.2.0 * **Deprecated:** Extending `SourceLocation` directly is deprecated. Instead, diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 95fa92ca3..37790ce92 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -246,6 +246,9 @@ abstract class FileSpan implements SourceSpanWithContext { /// The [file] that [this] belongs to. SourceFile get file; + FileLocation get start; + FileLocation get end; + /// Returns a new span that covers both [this] and [other]. /// /// Unlike [union], [other] may be disjoint from [this]. If it is, the text diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 25de799d7..4c703cdc2 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.2.0 +version: 1.2.1 author: Dart Team description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span From ee812d53fe33e40942e013220fabab5e859ea9ac Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 12 Jan 2016 17:23:05 -0800 Subject: [PATCH 022/128] Get rid of all the library tags. R=rnystrom@google.com Review URL: https://codereview.chromium.org//1583453004 . --- pkgs/source_span/lib/source_span.dart | 2 -- pkgs/source_span/lib/src/colors.dart | 2 -- pkgs/source_span/lib/src/file.dart | 2 -- pkgs/source_span/lib/src/location.dart | 2 -- pkgs/source_span/lib/src/location_mixin.dart | 2 -- pkgs/source_span/lib/src/span.dart | 2 -- pkgs/source_span/lib/src/span_exception.dart | 2 -- pkgs/source_span/lib/src/span_mixin.dart | 2 -- pkgs/source_span/lib/src/span_with_context.dart | 2 -- pkgs/source_span/lib/src/utils.dart | 2 -- 10 files changed, 20 deletions(-) diff --git a/pkgs/source_span/lib/source_span.dart b/pkgs/source_span/lib/source_span.dart index 9666dc296..6ed10a0e6 100644 --- a/pkgs/source_span/lib/source_span.dart +++ b/pkgs/source_span/lib/source_span.dart @@ -2,8 +2,6 @@ // 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. -library source_span; - export "src/file.dart"; export "src/location.dart"; export "src/location_mixin.dart"; diff --git a/pkgs/source_span/lib/src/colors.dart b/pkgs/source_span/lib/src/colors.dart index 274fc92af..e934cded7 100644 --- a/pkgs/source_span/lib/src/colors.dart +++ b/pkgs/source_span/lib/src/colors.dart @@ -3,8 +3,6 @@ // BSD-style license that can be found in the LICENSE file. // Color constants used for generating messages. -library source_span.colors; - const String RED = '\u001b[31m'; const String YELLOW = '\u001b[33m'; diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 37790ce92..1d39cf17a 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -2,8 +2,6 @@ // 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. -library source_span.file; - import 'dart:math' as math; import 'dart:typed_data'; diff --git a/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart index afb37c768..2d23db1a3 100644 --- a/pkgs/source_span/lib/src/location.dart +++ b/pkgs/source_span/lib/src/location.dart @@ -2,8 +2,6 @@ // 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. -library source_span.location; - import 'span.dart'; // TODO(nweiz): Use SourceLocationMixin once we decide to cut a release with diff --git a/pkgs/source_span/lib/src/location_mixin.dart b/pkgs/source_span/lib/src/location_mixin.dart index 5aa0de5ce..653c2c441 100644 --- a/pkgs/source_span/lib/src/location_mixin.dart +++ b/pkgs/source_span/lib/src/location_mixin.dart @@ -2,8 +2,6 @@ // 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. -library source_span.location_mixin; - import 'location.dart'; import 'span.dart'; diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index 9f150482c..fe1ac3956 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -2,8 +2,6 @@ // 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. -library source_span.span; - import 'location.dart'; import 'span_mixin.dart'; diff --git a/pkgs/source_span/lib/src/span_exception.dart b/pkgs/source_span/lib/src/span_exception.dart index 36f248832..ab0704614 100644 --- a/pkgs/source_span/lib/src/span_exception.dart +++ b/pkgs/source_span/lib/src/span_exception.dart @@ -2,8 +2,6 @@ // 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. -library source_span.span_exception; - import 'span.dart'; /// A class for exceptions that have source span information attached. diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index b4503facd..2d390b6a7 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -2,8 +2,6 @@ // 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. -library source_span.span_mixin; - import 'dart:math' as math; import 'package:path/path.dart' as p; diff --git a/pkgs/source_span/lib/src/span_with_context.dart b/pkgs/source_span/lib/src/span_with_context.dart index 0012e3f3d..1336b1225 100644 --- a/pkgs/source_span/lib/src/span_with_context.dart +++ b/pkgs/source_span/lib/src/span_with_context.dart @@ -2,8 +2,6 @@ // 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. -library source_span.span_with_context; - import 'location.dart'; import 'span.dart'; import 'utils.dart'; diff --git a/pkgs/source_span/lib/src/utils.dart b/pkgs/source_span/lib/src/utils.dart index fa0895784..69385476c 100644 --- a/pkgs/source_span/lib/src/utils.dart +++ b/pkgs/source_span/lib/src/utils.dart @@ -2,8 +2,6 @@ // 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. -library source_span.utils; - /// Returns the minimum of [obj1] and [obj2] according to /// [Comparable.compareTo]. Comparable min(Comparable obj1, Comparable obj2) => From 64d82cadae71b1b77c5b76b01a2fccee983a0a0c Mon Sep 17 00:00:00 2001 From: Vijay Menon Date: Tue, 23 Feb 2016 05:46:50 -0800 Subject: [PATCH 023/128] Make SourceSpanException.source a getter The override in https://github.com/dart-lang/string_scanner/blob/master/lib/src/exception.dart is causing a problem in DDC / strong mode. R=rnystrom@google.com Review URL: https://codereview.chromium.org//1722603005 . --- pkgs/source_span/lib/src/span_exception.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/lib/src/span_exception.dart b/pkgs/source_span/lib/src/span_exception.dart index ab0704614..921e62095 100644 --- a/pkgs/source_span/lib/src/span_exception.dart +++ b/pkgs/source_span/lib/src/span_exception.dart @@ -32,10 +32,13 @@ class SourceSpanException implements Exception { /// A [SourceSpanException] that's also a [FormatException]. class SourceSpanFormatException extends SourceSpanException implements FormatException { - final source; + final _source; + + // Subclasses may narrow the type. + dynamic get source => _source; int get offset => span == null ? null : span.start.offset; - SourceSpanFormatException(String message, SourceSpan span, [this.source]) + SourceSpanFormatException(String message, SourceSpan span, [this._source]) : super(message, span); } From cf91b57d90e500fce31fd5fc516c5d4948972560 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 2 Mar 2016 12:46:14 -0800 Subject: [PATCH 024/128] Allow some fields to be overridden in strong mode. For consistency, any field in a class that's meant to be extended can be overridden. R=lrn@google.com, rnystrom@google.com Review URL: https://codereview.chromium.org//1728113002 . --- pkgs/source_span/CHANGELOG.md | 5 +++++ pkgs/source_span/lib/src/span_exception.dart | 15 +++++++++------ pkgs/source_span/lib/src/span_with_context.dart | 6 ++++-- pkgs/source_span/pubspec.yaml | 2 +- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index ce7198068..cca6f11e6 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.2.2 + +* Allow `SourceSpanException.message`, `SourceSpanFormatException.source`, and + `SourceSpanWithContext.context` to be overridden in strong mode. + # 1.2.1 * Fix the declared type of `FileSpan.start` and `FileSpan.end`. In 1.2.0 these diff --git a/pkgs/source_span/lib/src/span_exception.dart b/pkgs/source_span/lib/src/span_exception.dart index 921e62095..6d3448b6c 100644 --- a/pkgs/source_span/lib/src/span_exception.dart +++ b/pkgs/source_span/lib/src/span_exception.dart @@ -6,15 +6,19 @@ import 'span.dart'; /// A class for exceptions that have source span information attached. class SourceSpanException implements Exception { + // This is a getter so that subclasses can override it. /// A message describing the exception. - final String message; + String get message => _message; + final String _message; + // This is a getter so that subclasses can override it. /// The span associated with this exception. /// /// This may be `null` if the source location can't be determined. - final SourceSpan span; + SourceSpan get span => _span; + final SourceSpan _span; - SourceSpanException(this.message, this.span); + SourceSpanException(this._message, this._span); /// Returns a string representation of [this]. /// @@ -32,10 +36,9 @@ class SourceSpanException implements Exception { /// A [SourceSpanException] that's also a [FormatException]. class SourceSpanFormatException extends SourceSpanException implements FormatException { - final _source; - - // Subclasses may narrow the type. + // This is a getter so that subclasses can override it. dynamic get source => _source; + final _source; int get offset => span == null ? null : span.start.offset; diff --git a/pkgs/source_span/lib/src/span_with_context.dart b/pkgs/source_span/lib/src/span_with_context.dart index 1336b1225..a02d78047 100644 --- a/pkgs/source_span/lib/src/span_with_context.dart +++ b/pkgs/source_span/lib/src/span_with_context.dart @@ -8,8 +8,10 @@ import 'utils.dart'; /// A class that describes a segment of source text with additional context. class SourceSpanWithContext extends SourceSpanBase { + // This is a getter so that subclasses can override it. /// Text around the span, which includes the line containing this span. - final String context; + String get context => _context; + final String _context; /// Creates a new span from [start] to [end] (exclusive) containing [text], in /// the given [context]. @@ -20,7 +22,7 @@ class SourceSpanWithContext extends SourceSpanBase { /// [text] should start at `start.column` from the beginning of a line in /// [context]. SourceSpanWithContext( - SourceLocation start, SourceLocation end, String text, this.context) + SourceLocation start, SourceLocation end, String text, this._context) : super(start, end, text) { if (!context.contains(text)) { throw new ArgumentError( diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 4c703cdc2..7ca7de46d 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.2.1 +version: 1.2.2 author: Dart Team description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span From 039fc63849e1c80df318aaf64403133509dba032 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 4 May 2016 14:40:03 -0700 Subject: [PATCH 025/128] Declare the package strong-mode clean. R=jmesserly@google.com Review URL: https://codereview.chromium.org//1955433002 . --- pkgs/source_span/.analysis_options | 2 ++ pkgs/source_span/test/utils_test.dart | 8 -------- 2 files changed, 2 insertions(+), 8 deletions(-) create mode 100644 pkgs/source_span/.analysis_options diff --git a/pkgs/source_span/.analysis_options b/pkgs/source_span/.analysis_options new file mode 100644 index 000000000..a10d4c5a0 --- /dev/null +++ b/pkgs/source_span/.analysis_options @@ -0,0 +1,2 @@ +analyzer: + strong-mode: true diff --git a/pkgs/source_span/test/utils_test.dart b/pkgs/source_span/test/utils_test.dart index 5d973f58a..2a86cc070 100644 --- a/pkgs/source_span/test/utils_test.dart +++ b/pkgs/source_span/test/utils_test.dart @@ -45,11 +45,3 @@ main() { }); }); } - -_linearSearch(list, predicate) { - if (list.length == 0) return -1; - for (int i = 0; i < list.length; i++) { - if (predicate(list[i])) return i; - } - return list.length; -} From 8732d800dfeeab614ffdcc83509ec91bc0dfc3b8 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 9 Jun 2016 15:37:44 -0700 Subject: [PATCH 026/128] Fix a message bug. If a point span appeared past the end of a file, and that file *didn't* end with a trailing newline, that span would be printed as though it pointed at the last character of the file. R=jmesserly@google.com Review URL: https://codereview.chromium.org//2056913002 . --- pkgs/source_span/CHANGELOG.md | 5 +++++ pkgs/source_span/lib/src/span_mixin.dart | 2 +- pkgs/source_span/pubspec.yaml | 2 +- pkgs/source_span/test/file_message_test.dart | 9 +++++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index cca6f11e6..d1bcda5ea 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.2.3 + +* Fix a bug where a point span at the end of a file without a trailing newline + would be printed incorrectly. + # 1.2.2 * Allow `SourceSpanException.message`, `SourceSpanFormatException.source`, and diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index 2d390b6a7..f6d04fa7c 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -70,7 +70,7 @@ abstract class SourceSpanMixin implements SourceSpan { } var endIndex = context.indexOf('\n'); textLine = endIndex == -1 ? context : context.substring(0, endIndex + 1); - column = math.min(column, textLine.length - 1); + column = math.min(column, textLine.length); } else { textLine = text.split("\n").first; column = 0; diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 7ca7de46d..3ef97ed13 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.2.2 +version: 1.2.3 author: Dart Team description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span diff --git a/pkgs/source_span/test/file_message_test.dart b/pkgs/source_span/test/file_message_test.dart index 5935c5882..d78a65172 100644 --- a/pkgs/source_span/test/file_message_test.dart +++ b/pkgs/source_span/test/file_message_test.dart @@ -59,6 +59,15 @@ zip zap zop ^""")); }); + test("works for a point span at the end of the file with no trailing newline", + () { + file = new SourceFile("zip zap zop"); + expect(file.location(11).pointSpan().message("oh no"), equals(""" +line 1, column 12: oh no +zip zap zop + ^""")); + }); + test("works for a point span in an empty file", () { expect(new SourceFile("").location(0).pointSpan().message("oh no"), equals(""" From 825a02483a28af9deb0eb9f0c7df98b1ad058f4d Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Mon, 17 Oct 2016 11:23:51 -0700 Subject: [PATCH 027/128] fix new strong mode error --- pkgs/source_span/lib/src/span_mixin.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index f6d04fa7c..a258cf5b4 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -60,7 +60,7 @@ abstract class SourceSpanMixin implements SourceSpan { if (length == 0 && this is! SourceSpanWithContext) return buffer.toString(); buffer.write("\n"); - var textLine; + String textLine; if (this is SourceSpanWithContext) { var context = (this as SourceSpanWithContext).context; var lineStart = findLineStart(context, text, column); From 9b64b5773486ba4ddc6149bd55e07015ea625791 Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Mon, 17 Oct 2016 11:24:47 -0700 Subject: [PATCH 028/128] update pubspec/changelog for 1.2.4 --- pkgs/source_span/CHANGELOG.md | 4 ++++ pkgs/source_span/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index d1bcda5ea..6da848706 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.2.4 + +* Fix a new strong mode error. + # 1.2.3 * Fix a bug where a point span at the end of a file without a trailing newline diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 3ef97ed13..9e41fdda0 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.2.3 +version: 1.2.4 author: Dart Team description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span From 1efa400c47aaedc47da778b46232fde591baf4cb Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 8 Nov 2016 11:35:21 -0800 Subject: [PATCH 029/128] Add SourceSpan.highlight(). (dart-lang/source_span#10) This is useful for constructing a message with a non-standard file/line/column display. --- pkgs/source_span/CHANGELOG.md | 5 ++ pkgs/source_span/lib/src/span.dart | 13 +++++ pkgs/source_span/lib/src/span_mixin.dart | 26 ++++++---- pkgs/source_span/pubspec.yaml | 2 +- ..._message_test.dart => highlight_test.dart} | 52 ++++++++++--------- pkgs/source_span/test/span_test.dart | 36 +------------ 6 files changed, 65 insertions(+), 69 deletions(-) rename pkgs/source_span/test/{file_message_test.dart => highlight_test.dart} (59%) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 6da848706..afcc49378 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.3.0 + +* Add `SourceSpan.highlight()`, which returns just the highlighted text that + would be included in `SourceSpan.message()`. + # 1.2.4 * Fix a new strong mode error. diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index fe1ac3956..599d66806 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -53,6 +53,19 @@ abstract class SourceSpan implements Comparable { /// should be highlighted using the default color. If it's `false` or `null`, /// it indicates that the text shouldn't be highlighted. String message(String message, {color}); + + /// Prints the text associated with this span in a user-friendly way. + /// + /// This is identical to [message], except that it doesn't print the file + /// name, line number, column number, or message. If [length] is 0 and this + /// isn't a [SourceSpanWithContext], returns an empty string. + /// + /// [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 + /// 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. + String highlight({color}); } /// A base class for source spans with [start], [end], and [text] known at diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index a258cf5b4..8d84ceaa7 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -46,20 +46,26 @@ abstract class SourceSpanMixin implements SourceSpan { } String message(String message, {color}) { - if (color == true) color = colors.RED; - if (color == false) color = null; - - var line = start.line; - var column = start.column; - var buffer = new StringBuffer(); - buffer.write('line ${line + 1}, column ${column + 1}'); + buffer.write('line ${start.line + 1}, column ${start.column + 1}'); if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}'); buffer.write(': $message'); - if (length == 0 && this is! SourceSpanWithContext) return buffer.toString(); - buffer.write("\n"); + var highlight = this.highlight(color: color); + if (!highlight.isEmpty) { + buffer.writeln(); + buffer.write(highlight); + } + + return buffer.toString(); + } + String highlight({color}) { + if (color == true) color = colors.RED; + if (color == false) color = null; + + var column = start.column; + var buffer = new StringBuffer(); String textLine; if (this is SourceSpanWithContext) { var context = (this as SourceSpanWithContext).context; @@ -71,6 +77,8 @@ abstract class SourceSpanMixin implements SourceSpan { var endIndex = context.indexOf('\n'); textLine = endIndex == -1 ? context : context.substring(0, endIndex + 1); column = math.min(column, textLine.length); + } else if (length == 0) { + return ""; } else { textLine = text.split("\n").first; column = 0; diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 9e41fdda0..8fa871120 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.2.4 +version: 1.3.0 author: Dart Team description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span diff --git a/pkgs/source_span/test/file_message_test.dart b/pkgs/source_span/test/highlight_test.dart similarity index 59% rename from pkgs/source_span/test/file_message_test.dart rename to pkgs/source_span/test/highlight_test.dart index d78a65172..32b09ff09 100644 --- a/pkgs/source_span/test/file_message_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -13,48 +13,42 @@ main() { foo bar baz whiz bang boom zip zap zop -""", url: "foo.dart"); +"""); }); test("points to the span in the source", () { - expect(file.span(4, 7).message("oh no"), equals(""" -line 1, column 5 of foo.dart: oh no + expect(file.span(4, 7).highlight(), equals(""" foo bar baz ^^^""")); }); test("gracefully handles a missing source URL", () { var span = new SourceFile("foo bar baz").span(4, 7); - expect(span.message("oh no"), equals(""" -line 1, column 5: oh no + expect(span.highlight(), equals(""" foo bar baz ^^^""")); }); test("highlights the first line of a multiline span", () { - expect(file.span(4, 20).message("oh no"), equals(""" -line 1, column 5 of foo.dart: oh no + expect(file.span(4, 20).highlight(), equals(""" foo bar baz ^^^^^^^^""")); }); test("works for a point span", () { - expect(file.location(4).pointSpan().message("oh no"), equals(""" -line 1, column 5 of foo.dart: oh no + expect(file.location(4).pointSpan().highlight(), equals(""" foo bar baz ^""")); }); test("works for a point span at the end of a line", () { - expect(file.location(11).pointSpan().message("oh no"), equals(""" -line 1, column 12 of foo.dart: oh no + expect(file.location(11).pointSpan().highlight(), equals(""" foo bar baz ^""")); }); test("works for a point span at the end of the file", () { - expect(file.location(38).pointSpan().message("oh no"), equals(""" -line 3, column 12 of foo.dart: oh no + expect(file.location(38).pointSpan().highlight(), equals(""" zip zap zop ^""")); }); @@ -62,46 +56,54 @@ zip zap zop test("works for a point span at the end of the file with no trailing newline", () { file = new SourceFile("zip zap zop"); - expect(file.location(11).pointSpan().message("oh no"), equals(""" -line 1, column 12: oh no + expect(file.location(11).pointSpan().highlight(), equals(""" zip zap zop ^""")); }); test("works for a point span in an empty file", () { - expect(new SourceFile("").location(0).pointSpan().message("oh no"), + expect(new SourceFile("").location(0).pointSpan().highlight(), equals(""" -line 1, column 1: oh no ^""")); }); test("works for a single-line file without a newline", () { - expect(new SourceFile("foo bar").span(0, 7).message("oh no"), + expect(new SourceFile("foo bar").span(0, 7).highlight(), equals(""" -line 1, column 1: oh no foo bar ^^^^^^^""")); }); + test("supports lines of preceding context", () { + var span = new SourceSpanWithContext( + new SourceLocation(5, line: 3, column: 5, sourceUrl: "foo.dart"), + new SourceLocation(12, line: 3, column: 12, sourceUrl: "foo.dart"), + "foo bar", + "previous\nlines\n-----foo bar-----\nfollowing line\n"); + + expect(span.highlight(color: colors.YELLOW), equals(""" +previous +lines +-----${colors.YELLOW}foo bar${colors.NONE}----- + ${colors.YELLOW}^^^^^^^${colors.NONE}""")); + }); + group("colors", () { test("doesn't colorize if color is false", () { - expect(file.span(4, 7).message("oh no", color: false), equals(""" -line 1, column 5 of foo.dart: oh no + expect(file.span(4, 7).highlight(color: false), equals(""" foo bar baz ^^^""")); }); test("colorizes if color is true", () { - expect(file.span(4, 7).message("oh no", color: true), equals(""" -line 1, column 5 of foo.dart: oh no + expect(file.span(4, 7).highlight(color: true), equals(""" foo ${colors.RED}bar${colors.NONE} baz ${colors.RED}^^^${colors.NONE}""")); }); test("uses the given color if it's passed", () { - expect(file.span(4, 7).message("oh no", color: colors.YELLOW), equals(""" -line 1, column 5 of foo.dart: oh no + expect(file.span(4, 7).highlight(color: colors.YELLOW), equals(""" foo ${colors.YELLOW}bar${colors.NONE} baz ${colors.YELLOW}^^^${colors.NONE}""")); }); diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart index 113848acf..f980f30cb 100644 --- a/pkgs/source_span/test/span_test.dart +++ b/pkgs/source_span/test/span_test.dart @@ -234,48 +234,16 @@ line 1, column 6 of foo.dart: oh no ${colors.YELLOW}foo bar${colors.NONE} ${colors.YELLOW}^^^^^^^${colors.NONE}""")); }); - }); - group("message() with context", () { - var spanWithContext; - setUp(() { - spanWithContext = new SourceSpanWithContext( + test("with context, underlines the right column", () { + var spanWithContext = new SourceSpanWithContext( new SourceLocation(5, sourceUrl: "foo.dart"), new SourceLocation(12, sourceUrl: "foo.dart"), "foo bar", "-----foo bar-----"); - }); - test("underlines under the right column", () { expect(spanWithContext.message("oh no", color: colors.YELLOW), equals(""" line 1, column 6 of foo.dart: oh no ------${colors.YELLOW}foo bar${colors.NONE}----- - ${colors.YELLOW}^^^^^^^${colors.NONE}""")); - }); - - test("underlines correctly when text appears twice", () { - var span = new SourceSpanWithContext( - new SourceLocation(9, column: 9, sourceUrl: "foo.dart"), - new SourceLocation(12, column: 12, sourceUrl: "foo.dart"), - "foo", - "-----foo foo-----"); - expect(span.message("oh no", color: colors.YELLOW), equals(""" -line 1, column 10 of foo.dart: oh no ------foo ${colors.YELLOW}foo${colors.NONE}----- - ${colors.YELLOW}^^^${colors.NONE}""")); - }); - - test("supports lines of preceeding context", () { - var span = new SourceSpanWithContext( - new SourceLocation(5, line: 3, column: 5, sourceUrl: "foo.dart"), - new SourceLocation(12, line: 3, column: 12, sourceUrl: "foo.dart"), - "foo bar", - "previous\nlines\n-----foo bar-----\nfollowing line\n"); - - expect(span.message("oh no", color: colors.YELLOW), equals(""" -line 4, column 6 of foo.dart: oh no -previous -lines -----${colors.YELLOW}foo bar${colors.NONE}----- ${colors.YELLOW}^^^^^^^${colors.NONE}""")); }); From 0158800db5273379101d5e0b57c249392858680b Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 6 Jan 2017 17:42:12 -0800 Subject: [PATCH 030/128] Fix tab highlighting. (dart-lang/source_span#14) --- pkgs/source_span/CHANGELOG.md | 5 +++++ pkgs/source_span/lib/src/span_mixin.dart | 12 +++++++++++- pkgs/source_span/pubspec.yaml | 3 ++- pkgs/source_span/test/highlight_test.dart | 7 +++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index afcc49378..0176b9f0b 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.3.1 + +* Properly highlight spans for lines that include tabs with + `SourceSpan.highlight()` and `SourceSpan.message()`. + # 1.3.0 * Add `SourceSpan.highlight()`, which returns just the highlighted text that diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index 8d84ceaa7..06e2024c9 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -3,6 +3,8 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:math' as math; + +import 'package:charcode/charcode.dart'; import 'package:path/path.dart' as p; import 'colors.dart' as colors; @@ -96,7 +98,15 @@ abstract class SourceSpanMixin implements SourceSpan { buffer.write(textLine); } if (!textLine.endsWith('\n')) buffer.write('\n'); - buffer.write(' ' * column); + + for (var i = 0; i < column; i++) { + if (textLine.codeUnitAt(i) == $tab) { + buffer.writeCharCode($tab); + } else { + buffer.writeCharCode($space); + } + } + if (color != null) buffer.write(color); buffer.write('^' * math.max(toColumn - column, 1)); if (color != null) buffer.write(colors.NONE); diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 8fa871120..d340d85cc 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,9 +1,10 @@ name: source_span -version: 1.3.0 +version: 1.3.1 author: Dart Team description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span dependencies: + charcode: '^1.0.0' path: '>=1.2.0 <2.0.0' environment: sdk: '>=0.8.10+6 <2.0.0' diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index 32b09ff09..74faed52a 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -75,6 +75,13 @@ foo bar ^^^^^^^""")); }); + test("emits tabs for tabs", () { + expect(new SourceFile(" \t \t\tfoo bar").span(5, 8).highlight(), + equals(""" + \t \t\tfoo bar + \t \t\t^^^""")); + }); + test("supports lines of preceding context", () { var span = new SourceSpanWithContext( new SourceLocation(5, line: 3, column: 5, sourceUrl: "foo.dart"), From 2829c3826c3e57e80e6ffcd5664653ca96cab105 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 6 Jan 2017 17:46:46 -0800 Subject: [PATCH 031/128] Update the SDK constraint. (dart-lang/source_span#15) If we're using ^ constraints, we need a tighter SDK constraint. --- pkgs/source_span/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index d340d85cc..70f4e108b 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -7,6 +7,6 @@ dependencies: charcode: '^1.0.0' path: '>=1.2.0 <2.0.0' environment: - sdk: '>=0.8.10+6 <2.0.0' + sdk: '>=1.8.0 <2.0.0' dev_dependencies: test: '>=0.12.0 <0.13.0' From 4d62afa97be1cd80f1404d91a5e5ce2faf42a7aa Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 16 May 2017 22:18:03 -0700 Subject: [PATCH 032/128] Deprecate the use of runes in SourceFile. (dart-lang/source_span#16) This behavior runs contrary to the rest of Dart's string handling, and in particular breaks string_scanner. See dart-lang/string_scannerdart-lang/source_span#4. --- pkgs/source_span/CHANGELOG.md | 13 +++++++++++++ pkgs/source_span/lib/src/file.dart | 19 ++++++++++++++++--- pkgs/source_span/pubspec.yaml | 2 +- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 0176b9f0b..68eafaaef 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,16 @@ +# 1.4.0 + +* The `new SourceFile()` constructor is deprecated. This constructed a source + file from a string's runes, rather than its code units, which runs counter to + the way Dart handles strings otherwise. The `new StringFile.fromString()` + constructor (see below) should be used instead. + +* The `new SourceFile.fromString()` constructor was added. This works like `new + SourceFile()`, except it uses code units rather than runes. + +* The current behavior when characters larger than `0xFFFF` are passed to `new + SourceFile.decoded()` is now considered deprecated. + # 1.3.1 * Properly highlight spans for lines that include tabs with diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 1d39cf17a..0217c2d43 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -49,15 +49,28 @@ class SourceFile { /// previous result. int _cachedLine; - /// Creates a new source file from [text]. + /// This constructor is deprecated. /// - /// [url] may be either a [String], a [Uri], or `null`. + /// Use [new SourceFile.fromString] instead. + @Deprecated("Will be removed in 2.0.0") SourceFile(String text, {url}) : this.decoded(text.runes, url: url); - /// Creates a new source file from a list of decoded characters. + /// Creates a new source file from [text]. /// /// [url] may be either a [String], a [Uri], or `null`. + SourceFile.fromString(String text, {url}) + : this.decoded(text.codeUnits, url: url); + + /// Creates a new source file from a list of decoded code units. + /// + /// [url] may be either a [String], a [Uri], or `null`. + /// + /// Currently, if [decodedChars] contains characters larger than `0xFFFF`, + /// they'll be treated as single characters rather than being split into + /// surrogate pairs. **This behavior is deprecated**. For + /// forwards-compatibility, callers should only pass in characters less than + /// or equal to `0xFFFF`. SourceFile.decoded(Iterable decodedChars, {url}) : url = url is String ? Uri.parse(url) : url, _decodedChars = new Uint32List.fromList(decodedChars.toList()) { diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 70f4e108b..46e3d522e 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.3.1 +version: 1.4.0 author: Dart Team description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span From 3f8bd495964fb7696edac168c4494417d98d9459 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Thu, 1 Mar 2018 15:49:51 -0800 Subject: [PATCH 033/128] Enable Travis-CI (dart-lang/source_span#19) Fixes dart-lang/source_span#18 --- pkgs/source_span/.travis.yml | 24 ++++ pkgs/source_span/lib/src/colors.dart | 1 - pkgs/source_span/lib/src/file.dart | 7 +- pkgs/source_span/lib/src/location.dart | 3 +- pkgs/source_span/lib/src/location_mixin.dart | 1 - pkgs/source_span/lib/src/span_mixin.dart | 4 +- .../lib/src/span_with_context.dart | 2 +- pkgs/source_span/test/file_test.dart | 12 +- pkgs/source_span/test/highlight_test.dart | 9 +- pkgs/source_span/test/location_test.dart | 13 +- pkgs/source_span/test/span_test.dart | 128 +++++++----------- 11 files changed, 98 insertions(+), 106 deletions(-) create mode 100644 pkgs/source_span/.travis.yml diff --git a/pkgs/source_span/.travis.yml b/pkgs/source_span/.travis.yml new file mode 100644 index 000000000..44a054287 --- /dev/null +++ b/pkgs/source_span/.travis.yml @@ -0,0 +1,24 @@ +language: dart + +dart: + - dev + - stable + +dart_task: + - test: --platform vm,chrome + +matrix: + include: + # Only validate formatting using the dev release + - dart: dev + dart_task: dartfmt + - dart: dev + dart_task: dartanalyzer + +# Only building master means that we don't run two builds for each pull request. +branches: + only: [master] + +cache: + directories: + - $HOME/.pub-cache diff --git a/pkgs/source_span/lib/src/colors.dart b/pkgs/source_span/lib/src/colors.dart index e934cded7..b9afab0db 100644 --- a/pkgs/source_span/lib/src/colors.dart +++ b/pkgs/source_span/lib/src/colors.dart @@ -8,4 +8,3 @@ const String RED = '\u001b[31m'; const String YELLOW = '\u001b[33m'; const String NONE = '\u001b[0m'; - diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 0217c2d43..6154e1343 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -53,8 +53,7 @@ class SourceFile { /// /// Use [new SourceFile.fromString] instead. @Deprecated("Will be removed in 2.0.0") - SourceFile(String text, {url}) - : this.decoded(text.runes, url: url); + SourceFile(String text, {url}) : this.decoded(text.runes, url: url); /// Creates a new source file from [text]. /// @@ -317,7 +316,6 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { SourceSpan union(SourceSpan other) { if (other is! FileSpan) return super.union(other); - _FileSpan span = expand(other); if (other is _FileSpan) { @@ -339,7 +337,8 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { return super == other && sourceUrl == other.sourceUrl; } - return _start == other._start && _end == other._end && + return _start == other._start && + _end == other._end && sourceUrl == other.sourceUrl; } diff --git a/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart index 2d23db1a3..cf9931951 100644 --- a/pkgs/source_span/lib/src/location.dart +++ b/pkgs/source_span/lib/src/location.dart @@ -82,7 +82,8 @@ class SourceLocation implements Comparable { } bool operator ==(other) => - other is SourceLocation && sourceUrl == other.sourceUrl && + other is SourceLocation && + sourceUrl == other.sourceUrl && offset == other.offset; int get hashCode => sourceUrl.hashCode + offset; diff --git a/pkgs/source_span/lib/src/location_mixin.dart b/pkgs/source_span/lib/src/location_mixin.dart index 653c2c441..1e5fc66f8 100644 --- a/pkgs/source_span/lib/src/location_mixin.dart +++ b/pkgs/source_span/lib/src/location_mixin.dart @@ -46,4 +46,3 @@ abstract class SourceLocationMixin implements SourceLocation { String toString() => '<$runtimeType: $offset $toolString>'; } - diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index 06e2024c9..1f7799d67 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -113,8 +113,8 @@ abstract class SourceSpanMixin implements SourceSpan { return buffer.toString(); } - bool operator ==(other) => other is SourceSpan && - start == other.start && end == other.end; + bool operator ==(other) => + other is SourceSpan && start == other.start && end == other.end; int get hashCode => start.hashCode + (31 * end.hashCode); diff --git a/pkgs/source_span/lib/src/span_with_context.dart b/pkgs/source_span/lib/src/span_with_context.dart index a02d78047..41697a0a6 100644 --- a/pkgs/source_span/lib/src/span_with_context.dart +++ b/pkgs/source_span/lib/src/span_with_context.dart @@ -22,7 +22,7 @@ class SourceSpanWithContext extends SourceSpanBase { /// [text] should start at `start.column` from the beginning of a line in /// [context]. SourceSpanWithContext( - SourceLocation start, SourceLocation end, String text, this._context) + SourceLocation start, SourceLocation end, String text, this._context) : super(start, end, text) { if (!context.contains(text)) { throw new ArgumentError( diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index 54bc3d34e..3f02a8bd9 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/test/file_test.dart @@ -87,7 +87,7 @@ zip zap zop""", url: "foo.dart"); test("column may not be outside the file", () { expect(() => file.getOffset(2, 100), throwsRangeError); }); - + test("column may not be outside the line", () { expect(() => file.getOffset(1, 20), throwsRangeError); }); @@ -109,8 +109,8 @@ zip zap zop""", url: "foo.dart"); group("for span().union()", () { test("source URLs must match", () { - var other = new SourceSpan( - new SourceLocation(10), new SourceLocation(11), "_"); + var other = + new SourceSpan(new SourceLocation(10), new SourceLocation(11), "_"); expect(() => file.span(9, 10).union(other), throwsArgumentError); }); @@ -312,10 +312,8 @@ zip zap zop""", url: "bar.dart").span(10, 11); }); test("returns a base SourceSpan for a SourceSpan input", () { - var other = new SourceSpan( - new SourceLocation(0, sourceUrl: "foo.dart"), - new SourceLocation(5, sourceUrl: "foo.dart"), - "hey, "); + var other = new SourceSpan(new SourceLocation(0, sourceUrl: "foo.dart"), + new SourceLocation(5, sourceUrl: "foo.dart"), "hey, "); var result = span.union(other); expect(result, isNot(new isInstanceOf())); expect(result.start, equals(other.start)); diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index 74faed52a..08d2e17c5 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -62,22 +62,19 @@ zip zap zop }); test("works for a point span in an empty file", () { - expect(new SourceFile("").location(0).pointSpan().highlight(), - equals(""" + expect(new SourceFile("").location(0).pointSpan().highlight(), equals(""" ^""")); }); test("works for a single-line file without a newline", () { - expect(new SourceFile("foo bar").span(0, 7).highlight(), - equals(""" + expect(new SourceFile("foo bar").span(0, 7).highlight(), equals(""" foo bar ^^^^^^^""")); }); test("emits tabs for tabs", () { - expect(new SourceFile(" \t \t\tfoo bar").span(5, 8).highlight(), - equals(""" + expect(new SourceFile(" \t \t\tfoo bar").span(5, 8).highlight(), equals(""" \t \t\tfoo bar \t \t\t^^^""")); }); diff --git a/pkgs/source_span/test/location_test.dart b/pkgs/source_span/test/location_test.dart index dcd497a9f..3a32a92ef 100644 --- a/pkgs/source_span/test/location_test.dart +++ b/pkgs/source_span/test/location_test.dart @@ -8,8 +8,8 @@ import 'package:source_span/source_span.dart'; main() { var location; setUp(() { - location = new SourceLocation(15, - line: 2, column: 6, sourceUrl: "foo.dart"); + location = + new SourceLocation(15, line: 2, column: 6, sourceUrl: "foo.dart"); }); group('errors', () { @@ -28,13 +28,13 @@ main() { }); test('for distance() source URLs must match', () { - expect(() => location.distance(new SourceLocation(0)), - throwsArgumentError); + expect( + () => location.distance(new SourceLocation(0)), throwsArgumentError); }); test('for compareTo() source URLs must match', () { - expect(() => location.compareTo(new SourceLocation(0)), - throwsArgumentError); + expect( + () => location.compareTo(new SourceLocation(0)), throwsArgumentError); }); }); @@ -81,7 +81,6 @@ main() { }); }); - group("equality", () { test("two locations with the same offset and source are equal", () { var other = new SourceLocation(15, sourceUrl: "foo.dart"); diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart index f980f30cb..b7637cf7c 100644 --- a/pkgs/source_span/test/span_test.dart +++ b/pkgs/source_span/test/span_test.dart @@ -9,10 +9,8 @@ import 'package:source_span/src/colors.dart' as colors; main() { var span; setUp(() { - span = new SourceSpan( - new SourceLocation(5, sourceUrl: "foo.dart"), - new SourceLocation(12, sourceUrl: "foo.dart"), - "foo bar"); + span = new SourceSpan(new SourceLocation(5, sourceUrl: "foo.dart"), + new SourceLocation(12, sourceUrl: "foo.dart"), "foo bar"); }); group('errors', () { @@ -40,26 +38,28 @@ main() { test('context must contain text', () { var start = new SourceLocation(2); var end = new SourceLocation(5); - expect(() => new SourceSpanWithContext( - start, end, "abc", "--axc--"), throwsArgumentError); + expect(() => new SourceSpanWithContext(start, end, "abc", "--axc--"), + throwsArgumentError); }); test('text starts at start.column in context', () { var start = new SourceLocation(3); var end = new SourceLocation(5); - expect(() => new SourceSpanWithContext( - start, end, "abc", "--abc--"), throwsArgumentError); + expect(() => new SourceSpanWithContext(start, end, "abc", "--abc--"), + throwsArgumentError); }); test('text starts at start.column of line in multi-line context', () { var start = new SourceLocation(4, line: 55, column: 3); var end = new SourceLocation(7, line: 55, column: 6); - expect(() => new SourceSpanWithContext( - start, end, "abc", "\n--abc--"), throwsArgumentError); - expect(() => new SourceSpanWithContext( - start, end, "abc", "\n----abc--"), throwsArgumentError); - expect(() => new SourceSpanWithContext( - start, end, "abc", "\n\n--abc--"), throwsArgumentError); + expect(() => new SourceSpanWithContext(start, end, "abc", "\n--abc--"), + throwsArgumentError); + expect( + () => new SourceSpanWithContext(start, end, "abc", "\n----abc--"), + throwsArgumentError); + expect( + () => new SourceSpanWithContext(start, end, "abc", "\n\n--abc--"), + throwsArgumentError); // However, these are valid: new SourceSpanWithContext(start, end, "abc", "\n---abc--"); @@ -75,10 +75,14 @@ main() { new SourceSpanWithContext(start1, end1, "abc", "--abc--abc--\n"); new SourceSpanWithContext(start2, end2, "abc", "--abc---abc--\n"); new SourceSpanWithContext(start2, end2, "abc", "---abc--abc--\n"); - expect(() => new SourceSpanWithContext( - start1, end1, "abc", "---abc--abc--\n"), throwsArgumentError); - expect(() => new SourceSpanWithContext( - start2, end2, "abc", "--abc--abc--\n"), throwsArgumentError); + expect( + () => new SourceSpanWithContext( + start1, end1, "abc", "---abc--abc--\n"), + throwsArgumentError); + expect( + () => new SourceSpanWithContext( + start2, end2, "abc", "--abc--abc--\n"), + throwsArgumentError); }); }); @@ -103,10 +107,8 @@ main() { }); test('for compareTo() source URLs must match', () { - var other = new SourceSpan( - new SourceLocation(12, sourceUrl: "bar.dart"), - new SourceLocation(13, sourceUrl: "bar.dart"), - "_"); + var other = new SourceSpan(new SourceLocation(12, sourceUrl: "bar.dart"), + new SourceLocation(13, sourceUrl: "bar.dart"), "_"); expect(() => span.compareTo(other), throwsArgumentError); }); @@ -121,10 +123,8 @@ main() { group("union()", () { test("works with a preceding adjacent span", () { - var other = new SourceSpan( - new SourceLocation(0, sourceUrl: "foo.dart"), - new SourceLocation(5, sourceUrl: "foo.dart"), - "hey, "); + var other = new SourceSpan(new SourceLocation(0, sourceUrl: "foo.dart"), + new SourceLocation(5, sourceUrl: "foo.dart"), "hey, "); var result = span.union(other); expect(result.start, equals(other.start)); @@ -133,10 +133,8 @@ main() { }); test("works with a preceding overlapping span", () { - var other = new SourceSpan( - new SourceLocation(0, sourceUrl: "foo.dart"), - new SourceLocation(8, sourceUrl: "foo.dart"), - "hey, foo"); + var other = new SourceSpan(new SourceLocation(0, sourceUrl: "foo.dart"), + new SourceLocation(8, sourceUrl: "foo.dart"), "hey, foo"); var result = span.union(other); expect(result.start, equals(other.start)); @@ -145,10 +143,8 @@ main() { }); test("works with a following adjacent span", () { - var other = new SourceSpan( - new SourceLocation(12, sourceUrl: "foo.dart"), - new SourceLocation(16, sourceUrl: "foo.dart"), - " baz"); + var other = new SourceSpan(new SourceLocation(12, sourceUrl: "foo.dart"), + new SourceLocation(16, sourceUrl: "foo.dart"), " baz"); var result = span.union(other); expect(result.start, equals(span.start)); @@ -157,10 +153,8 @@ main() { }); test("works with a following overlapping span", () { - var other = new SourceSpan( - new SourceLocation(9, sourceUrl: "foo.dart"), - new SourceLocation(16, sourceUrl: "foo.dart"), - "bar baz"); + var other = new SourceSpan(new SourceLocation(9, sourceUrl: "foo.dart"), + new SourceLocation(16, sourceUrl: "foo.dart"), "bar baz"); var result = span.union(other); expect(result.start, equals(span.start)); @@ -169,19 +163,15 @@ main() { }); test("works with an internal overlapping span", () { - var other = new SourceSpan( - new SourceLocation(7, sourceUrl: "foo.dart"), - new SourceLocation(10, sourceUrl: "foo.dart"), - "o b"); + var other = new SourceSpan(new SourceLocation(7, sourceUrl: "foo.dart"), + new SourceLocation(10, sourceUrl: "foo.dart"), "o b"); expect(span.union(other), equals(span)); }); test("works with an external overlapping span", () { - var other = new SourceSpan( - new SourceLocation(0, sourceUrl: "foo.dart"), - new SourceLocation(16, sourceUrl: "foo.dart"), - "hey, foo bar baz"); + var other = new SourceSpan(new SourceLocation(0, sourceUrl: "foo.dart"), + new SourceLocation(16, sourceUrl: "foo.dart"), "hey, foo bar baz"); expect(span.union(other), equals(other)); }); @@ -206,11 +196,10 @@ foo bar }); test("gracefully handles empty text", () { - var span = new SourceSpan( - new SourceLocation(5), new SourceLocation(5), ""); + var span = + new SourceSpan(new SourceLocation(5), new SourceLocation(5), ""); - expect(span.message("oh no"), - equals("line 1, column 6: oh no")); + expect(span.message("oh no"), equals("line 1, column 6: oh no")); }); test("doesn't colorize if color is false", () { @@ -221,8 +210,7 @@ foo bar }); test("colorizes if color is true", () { - expect(span.message("oh no", color: true), - equals(""" + expect(span.message("oh no", color: true), equals(""" line 1, column 6 of foo.dart: oh no ${colors.RED}foo bar${colors.NONE} ${colors.RED}^^^^^^^${colors.NONE}""")); @@ -251,20 +239,16 @@ line 1, column 6 of foo.dart: oh no group("compareTo()", () { test("sorts by start location first", () { - var other = new SourceSpan( - new SourceLocation(6, sourceUrl: "foo.dart"), - new SourceLocation(14, sourceUrl: "foo.dart"), - "oo bar b"); + var other = new SourceSpan(new SourceLocation(6, sourceUrl: "foo.dart"), + new SourceLocation(14, sourceUrl: "foo.dart"), "oo bar b"); expect(span.compareTo(other), lessThan(0)); expect(other.compareTo(span), greaterThan(0)); }); test("sorts by length second", () { - var other = new SourceSpan( - new SourceLocation(5, sourceUrl: "foo.dart"), - new SourceLocation(14, sourceUrl: "foo.dart"), - "foo bar b"); + var other = new SourceSpan(new SourceLocation(5, sourceUrl: "foo.dart"), + new SourceLocation(14, sourceUrl: "foo.dart"), "foo bar b"); expect(span.compareTo(other), lessThan(0)); expect(other.compareTo(span), greaterThan(0)); @@ -277,37 +261,29 @@ line 1, column 6 of foo.dart: oh no group("equality", () { test("two spans with the same locations are equal", () { - var other = new SourceSpan( - new SourceLocation(5, sourceUrl: "foo.dart"), - new SourceLocation(12, sourceUrl: "foo.dart"), - "foo bar"); + var other = new SourceSpan(new SourceLocation(5, sourceUrl: "foo.dart"), + new SourceLocation(12, sourceUrl: "foo.dart"), "foo bar"); expect(span, equals(other)); }); test("a different start isn't equal", () { - var other = new SourceSpan( - new SourceLocation(0, sourceUrl: "foo.dart"), - new SourceLocation(12, sourceUrl: "foo.dart"), - "hey, foo bar"); + var other = new SourceSpan(new SourceLocation(0, sourceUrl: "foo.dart"), + new SourceLocation(12, sourceUrl: "foo.dart"), "hey, foo bar"); expect(span, isNot(equals(other))); }); test("a different end isn't equal", () { - var other = new SourceSpan( - new SourceLocation(5, sourceUrl: "foo.dart"), - new SourceLocation(16, sourceUrl: "foo.dart"), - "foo bar baz"); + var other = new SourceSpan(new SourceLocation(5, sourceUrl: "foo.dart"), + new SourceLocation(16, sourceUrl: "foo.dart"), "foo bar baz"); expect(span, isNot(equals(other))); }); test("a different source URL isn't equal", () { - var other = new SourceSpan( - new SourceLocation(5, sourceUrl: "bar.dart"), - new SourceLocation(12, sourceUrl: "bar.dart"), - "foo bar"); + var other = new SourceSpan(new SourceLocation(5, sourceUrl: "bar.dart"), + new SourceLocation(12, sourceUrl: "bar.dart"), "foo bar"); expect(span, isNot(equals(other))); }); From 67cb71299015780b813612862109596ee0a6243b Mon Sep 17 00:00:00 2001 From: BC Ko Date: Thu, 24 May 2018 02:56:36 -0700 Subject: [PATCH 034/128] Update .gitignore to new `dart_tool` pub cache dart-lang/sdkdart-lang/source_span#32030 --- pkgs/source_span/.gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkgs/source_span/.gitignore b/pkgs/source_span/.gitignore index 7dbf0350d..ab3cb76e6 100644 --- a/pkgs/source_span/.gitignore +++ b/pkgs/source_span/.gitignore @@ -1,5 +1,6 @@ # Don’t commit the following directories created by pub. .buildlog +.dart_tool/ .pub/ build/ packages @@ -12,4 +13,4 @@ packages *.js.map # Include when developing application packages. -pubspec.lock \ No newline at end of file +pubspec.lock From 38f80e287fceeba4b135076c6a76f8a5cc160140 Mon Sep 17 00:00:00 2001 From: Aske Simon Christensen Date: Fri, 6 Jul 2018 22:15:15 +0200 Subject: [PATCH 035/128] Avoid uninitialized final fields. (dart-lang/source_span#22) --- pkgs/source_span/lib/src/span.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index 599d66806..ff5c4b0dc 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -8,22 +8,22 @@ import 'span_mixin.dart'; /// A class that describes a segment of source text. abstract class SourceSpan implements Comparable { /// The start location of this span. - final SourceLocation start; + SourceLocation get start; /// The end location of this span, exclusive. - final SourceLocation end; + SourceLocation get end; /// The source text for this span. - final String text; + String get text; /// The URL of the source (typically a file) of this span. /// /// This may be null, indicating that the source URL is unknown or /// unavailable. - final Uri sourceUrl; + Uri get sourceUrl; /// The length of this span, in characters. - final int length; + int get length; /// Creates a new span from [start] to [end] (exclusive) containing [text]. /// From 4359f93cfec83b03e4141d63273929a36d948cfa Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Wed, 18 Jul 2018 16:50:44 -0400 Subject: [PATCH 036/128] chore: set max SDK version to <3.0.0 (dart-lang/source_span#23) --- pkgs/source_span/.analysis_options | 2 -- pkgs/source_span/CHANGELOG.md | 4 ++++ pkgs/source_span/pubspec.yaml | 16 ++++++++++------ pkgs/source_span/test/file_test.dart | 8 ++++---- pkgs/source_span/test/highlight_test.dart | 15 +++++++++------ 5 files changed, 27 insertions(+), 18 deletions(-) delete mode 100644 pkgs/source_span/.analysis_options diff --git a/pkgs/source_span/.analysis_options b/pkgs/source_span/.analysis_options deleted file mode 100644 index a10d4c5a0..000000000 --- a/pkgs/source_span/.analysis_options +++ /dev/null @@ -1,2 +0,0 @@ -analyzer: - strong-mode: true diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 68eafaaef..53a700cf1 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.4.1 + +* Set max SDK version to `<3.0.0`, and adjust other dependencies. + # 1.4.0 * The `new SourceFile()` constructor is deprecated. This constructed a source diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 46e3d522e..1d5321007 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,12 +1,16 @@ name: source_span -version: 1.4.0 -author: Dart Team +version: 1.4.1 + description: A library for identifying source spans and locations. +author: Dart Team homepage: https://github.com/dart-lang/source_span + +environment: + sdk: '>=1.8.0 <3.0.0' + dependencies: - charcode: '^1.0.0' + charcode: ^1.0.0 path: '>=1.2.0 <2.0.0' -environment: - sdk: '>=1.8.0 <2.0.0' + dev_dependencies: - test: '>=0.12.0 <0.13.0' + test: '>=0.12.0 <2.0.0' diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index 3f02a8bd9..071f3f9d7 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/test/file_test.dart @@ -8,7 +8,7 @@ import 'package:source_span/source_span.dart'; main() { var file; setUp(() { - file = new SourceFile(""" + file = new SourceFile.fromString(""" foo bar baz whiz bang boom zip zap zop""", url: "foo.dart"); @@ -122,7 +122,7 @@ zip zap zop""", url: "foo.dart"); }); test("for span().expand() source URLs must match", () { - var other = new SourceFile(""" + var other = new SourceFile.fromString(""" foo bar baz whiz bang boom zip zap zop""", url: "bar.dart").span(10, 11); @@ -139,11 +139,11 @@ zip zap zop""", url: "bar.dart").span(10, 11); group("new SourceFile()", () { test("handles CRLF correctly", () { - expect(new SourceFile("foo\r\nbar").getLine(6), equals(1)); + expect(new SourceFile.fromString("foo\r\nbar").getLine(6), equals(1)); }); test("handles a lone CR correctly", () { - expect(new SourceFile("foo\rbar").getLine(5), equals(1)); + expect(new SourceFile.fromString("foo\rbar").getLine(5), equals(1)); }); }); diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index 08d2e17c5..ac8334bd5 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -9,7 +9,7 @@ import 'package:source_span/src/colors.dart' as colors; main() { var file; setUp(() { - file = new SourceFile(""" + file = new SourceFile.fromString(""" foo bar baz whiz bang boom zip zap zop @@ -23,7 +23,7 @@ foo bar baz }); test("gracefully handles a missing source URL", () { - var span = new SourceFile("foo bar baz").span(4, 7); + var span = new SourceFile.fromString("foo bar baz").span(4, 7); expect(span.highlight(), equals(""" foo bar baz ^^^""")); @@ -55,26 +55,29 @@ zip zap zop test("works for a point span at the end of the file with no trailing newline", () { - file = new SourceFile("zip zap zop"); + file = new SourceFile.fromString("zip zap zop"); expect(file.location(11).pointSpan().highlight(), equals(""" zip zap zop ^""")); }); test("works for a point span in an empty file", () { - expect(new SourceFile("").location(0).pointSpan().highlight(), equals(""" + expect(new SourceFile.fromString("").location(0).pointSpan().highlight(), + equals(""" ^""")); }); test("works for a single-line file without a newline", () { - expect(new SourceFile("foo bar").span(0, 7).highlight(), equals(""" + expect( + new SourceFile.fromString("foo bar").span(0, 7).highlight(), equals(""" foo bar ^^^^^^^""")); }); test("emits tabs for tabs", () { - expect(new SourceFile(" \t \t\tfoo bar").span(5, 8).highlight(), equals(""" + expect(new SourceFile.fromString(" \t \t\tfoo bar").span(5, 8).highlight(), + equals(""" \t \t\tfoo bar \t \t\t^^^""")); }); From 328a91696b1f6ea03b581dd144eef4c8d861e441 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Thu, 13 Dec 2018 14:09:07 -0800 Subject: [PATCH 037/128] Fix typo and add example to message() and highlight() (dart-lang/source_span#24) --- pkgs/source_span/lib/src/span.dart | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index ff5c4b0dc..19655a54a 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -48,10 +48,12 @@ abstract class SourceSpan implements Comparable { /// Formats [message] in a human-friendly way associated with this span. /// /// [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 - /// 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. + /// it indicates an [ANSI terminal color + /// escape](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) that should + /// be used to highlight the span's text (for example, `"\u001b[31m"` will + /// color red). 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. String message(String message, {color}); /// Prints the text associated with this span in a user-friendly way. @@ -61,10 +63,12 @@ abstract class SourceSpan implements Comparable { /// isn't a [SourceSpanWithContext], returns an empty string. /// /// [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 - /// 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. + /// it indicates an [ANSI terminal color + /// escape](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) that should + /// be used to highlight the span's text (for example, `"\u001b[31m"` will + /// color red). 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. String highlight({color}); } From c084ccd037399473e3c88ad79a48e937049cbf7c Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 20 Dec 2018 14:34:28 -0800 Subject: [PATCH 038/128] Improve span highlighting * Fully highlights multiline spans. * Includes line numbers. * Uses Unicode glyphs for highlighting when available. * Includes context after the last line of the span for a manually-constructed SourceSpanWithContext. This draws heavy inspiration from Rust's multiline error highlighting. --- pkgs/source_span/CHANGELOG.md | 11 + pkgs/source_span/lib/src/colors.dart | 2 + pkgs/source_span/lib/src/highlighter.dart | 354 ++++++++++++++++++++++ pkgs/source_span/lib/src/span.dart | 10 + pkgs/source_span/lib/src/span_mixin.dart | 55 +--- pkgs/source_span/lib/src/utils.dart | 34 ++- pkgs/source_span/pubspec.yaml | 3 +- pkgs/source_span/test/highlight_test.dart | 331 +++++++++++++++++--- pkgs/source_span/test/span_test.dart | 48 ++- pkgs/source_span/test/utils_test.dart | 11 + 10 files changed, 749 insertions(+), 110 deletions(-) create mode 100644 pkgs/source_span/lib/src/highlighter.dart diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 53a700cf1..2248a3937 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,14 @@ +# 1.5.0 + +* Improve the output of `SourceSpan.highlight()` and `SourceSpan.message()`: + + * They now include line numbers. + * They will now print every line of a multiline span. + * They will now use Unicode box-drawing characters by default (this can be + controlled using [`term_glyph.ascii`][]). + +[`term_glyph.ascii`]: https://pub.dartlang.org/documentation/term_glyph/latest/term_glyph/ascii.html + # 1.4.1 * Set max SDK version to `<3.0.0`, and adjust other dependencies. diff --git a/pkgs/source_span/lib/src/colors.dart b/pkgs/source_span/lib/src/colors.dart index b9afab0db..2931eea9e 100644 --- a/pkgs/source_span/lib/src/colors.dart +++ b/pkgs/source_span/lib/src/colors.dart @@ -7,4 +7,6 @@ const String RED = '\u001b[31m'; const String YELLOW = '\u001b[33m'; +const String BLUE = '\u001b[34m'; + const String NONE = '\u001b[0m'; diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart new file mode 100644 index 000000000..bc0fe6981 --- /dev/null +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -0,0 +1,354 @@ +// Copyright (c) 2018, 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 'dart:math' as math; + +import 'package:charcode/charcode.dart'; +import 'package:term_glyph/term_glyph.dart' as glyph; + +import 'colors.dart' as colors; +import 'location.dart'; +import 'span.dart'; +import 'span_with_context.dart'; +import 'utils.dart'; + +/// A class for writing a chunk of text with a particular span highlighted. +class Highlighter { + /// The span to highlight. + final SourceSpanWithContext _span; + + /// The color to highlight [_span] within its context, or `null` if the span + /// should not be colored. + final String _color; + + /// Whether [_span] covers multiple lines. + final bool _multiline; + + /// The number of characters before the bar in the sidebar. + final int _paddingBeforeSidebar; + + // The number of characters between the bar in the sidebar and the text + // being highlighted. + int get _paddingAfterSidebar => + // This is just a space for a single-line span, but for a multi-line span + // needs to accommodate " | ". + _multiline ? 3 : 1; + + /// The buffer to which to write the result. + final _buffer = new StringBuffer(); + + /// The number of spaces to render for hard tabs that appear in `_span.text`. + /// + /// We don't want to render raw tabs, because they'll mess up our character + /// alignment. + static const _spacesPerTab = 4; + + factory Highlighter(SourceSpan span, {color}) { + if (color == true) color = colors.RED; + if (color == false) color = null; + + // Normalize [span] to ensure that it's a [SourceSpanWithContext] whose + // context actually contains its text at the expected column. If it's not, + // adjust the start and end locations' line and column fields so that the + // highlighter can assume they match up with the context. + SourceSpanWithContext newSpan; + if (span is SourceSpanWithContext && + findLineStart(span.context, span.text, span.start.column) != null) { + newSpan = span; + } else { + newSpan = new SourceSpanWithContext( + new SourceLocation(span.start.offset, + sourceUrl: span.sourceUrl, line: 0, column: 0), + new SourceLocation(span.end.offset, + sourceUrl: span.sourceUrl, + line: countCodeUnits(span.text, $lf), + column: _lastColumn(span.text)), + span.text, + span.text); + } + + // Normalize [span] to remove a trailing newline from `span.context`. If + // necessary, also adjust `span.end` so that it doesn't point past where the + // trailing newline used to be. + if (newSpan.context.endsWith("\n")) { + var context = newSpan.context.substring(0, newSpan.context.length - 1); + + var text = newSpan.text; + var start = newSpan.start; + var end = newSpan.end; + if (newSpan.text.endsWith("\n") && _isTextAtEndOfContext(newSpan)) { + text = newSpan.text.substring(0, newSpan.text.length - 1); + end = new SourceLocation(newSpan.end.offset - 1, + sourceUrl: newSpan.sourceUrl, + line: newSpan.end.line - 1, + column: _lastColumn(text)); + start = + newSpan.start.offset == newSpan.end.offset ? end : newSpan.start; + } + newSpan = new SourceSpanWithContext(start, end, text, context); + } + + return new Highlighter._(newSpan, color); + } + + /// Returns the (0-based) column number of the last column of the last line in [text]. + static int _lastColumn(String text) => + text.length - text.lastIndexOf("\n") + 1; + + /// Returns whether [span]'s text runs all the way to the end of its context. + static bool _isTextAtEndOfContext(SourceSpanWithContext span) => + findLineStart(span.context, span.text, span.start.column) + + span.start.column + + span.length == + span.context.length; + + Highlighter._(this._span, this._color) + : _multiline = _span.start.line != _span.end.line, + // In a purely mathematical world, floor(log10(n)) would give the number of + // digits in n, but floating point errors render that unreliable in + // practice. + _paddingBeforeSidebar = _span.end.line.toString().length + 1; + + /// Returns the highlighted span text. + /// + /// This method should only be called once. + String highlight() { + //if (_span.length == 0 && _span.context.isEmpty) return ""; + + _writeSidebar(end: glyph.downEnd); + _buffer.writeln(); + + // If [context] contains lines prior to the one [text] appears on, write + // those first. + var lineStart = + findLineStart(_span.context, _span.text, _span.start.column); + assert(lineStart != null); // enfoced by [new Highlighter] + + var context = _span.context; + if (lineStart > 0) { + // Take a substring to one character *before* [lineStart] because + // [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"); + var lineNumber = _span.start.line - lines.length; + for (var line in lines) { + _writeSidebar(line: lineNumber); + _buffer.write(" " * _paddingAfterSidebar); + _writeText(line); + _buffer.writeln(); + lineNumber++; + } + context = context.substring(lineStart); + } + + var lines = context.split("\n"); + + // Trim a trailing newline so we don't add an empty line to the end of the + // highlight. + if (lines.last.isEmpty && lines.length > 1) lines.removeLast(); + + _writeFirstLine(lines.first); + if (_multiline) { + _writeIntermediateLines( + lines.skip(1).take(_span.end.line - _span.start.line - 1)); + _writeLastLine(lines[_span.end.line - _span.start.line]); + } + _writeTrailingLines(lines.skip(1 + _span.end.line - _span.start.line)); + + _writeSidebar(end: glyph.upEnd); + + return _buffer.toString(); + } + + // Writes the first (and possibly only) line highlighted by the span. + void _writeFirstLine(String line) { + _writeSidebar(line: _span.start.line); + + 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); + + // 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(" "); + _writeText(line); + }); + _buffer.writeln(); + return; + } + + _buffer.write(" " * _paddingAfterSidebar); + _writeText(textBefore); + var 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); + startColumn = startColumn + tabsBefore * (_spacesPerTab - 1); + endColumn = endColumn + (tabsBefore + tabsInside) * (_spacesPerTab - 1); + + // Write the highlight for the first line. This is a series of carets for a + // single-line span, and a pointer to the beginning of a multi-line span. + _writeSidebar(); + if (_multiline) { + _buffer.write(" "); + _colorize(() { + _buffer.write(glyph.topLeftCorner); + _buffer.write(glyph.horizontalLine * (startColumn + 1)); + _buffer.write("^"); + }); + } else { + _buffer.write(" " * (startColumn + 1)); + _colorize( + () => _buffer.write("^" * math.max(endColumn - startColumn, 1))); + } + _buffer.writeln(); + } + + /// Writes the lines between the first and last lines highlighted by the span. + void _writeIntermediateLines(Iterable lines) { + assert(_multiline); + + // +1 because the first line was already written. + var lineNumber = _span.start.line + 1; + for (var line in lines) { + _writeSidebar(line: lineNumber); + + _buffer.write(" "); + _colorize(() { + _buffer.write(glyph.verticalLine); + _buffer.write(" "); + _writeText(line); + }); + _buffer.writeln(); + + lineNumber++; + } + } + + // Writes the last line highlighted by the span. + void _writeLastLine(String line) { + assert(_multiline); + + _writeSidebar(line: _span.end.line); + + var endColumn = math.min(_span.end.column, line.length); + + // If the span covers the entire last line, don't bother pointing out + // exactly where it ends. + if (_multiline && endColumn == line.length) { + _buffer.write(" "); + _colorize(() { + _buffer.write(glyph.glyphOrAscii("└", "\\")); + _buffer.write(" "); + _writeText(line); + }); + _buffer.writeln(); + return; + } + + _buffer.write(" "); + var textInside = line.substring(0, endColumn); + _colorize(() { + _buffer.write(glyph.verticalLine); + _buffer.write(" "); + _writeText(textInside); + }); + _writeText(line.substring(endColumn)); + _buffer.writeln(); + + // Adjust the end column to account for any tabs that were converted to + // spaces. + var tabsInside = _countTabs(textInside); + endColumn = endColumn + tabsInside * (_spacesPerTab - 1); + + // Write the highlight for the final line, which is an arrow pointing to the + // end of the span. + _writeSidebar(); + _buffer.write(" "); + _colorize(() { + _buffer.write(glyph.bottomLeftCorner); + _buffer.write(glyph.horizontalLine * endColumn); + _buffer.write("^"); + }); + _buffer.writeln(); + } + + /// Writes lines that appear in the context string but come after the span. + void _writeTrailingLines(Iterable lines) { + // +1 because this comes after any lines covered by the span. + var lineNumber = _span.end.line + 1; + for (var line in lines) { + _writeSidebar(line: lineNumber); + _buffer.write(" " * _paddingAfterSidebar); + _writeText(line); + _buffer.writeln(); + lineNumber++; + } + } + + /// Writes a snippet from the source text, converting hard tab characters into + /// plain indentation. + void _writeText(String text) { + for (var char in text.codeUnits) { + if (char == $tab) { + _buffer.write(" " * _spacesPerTab); + } else { + _buffer.writeCharCode(char); + } + } + } + + // Writes a sidebar to [buffer] that includes [line] as the line number if + // given and writes [end] at the end (defaults to [glyphs.verticalLine]). + void _writeSidebar({int line, String end}) { + _colorize(() { + if (line != null) { + // Add 1 to line to convert from computer-friendly 0-indexed line + // numbers to human-friendly 1-indexed line numbers. + _buffer.write((line + 1).toString().padRight(_paddingBeforeSidebar)); + } else { + _buffer.write(" " * _paddingBeforeSidebar); + } + _buffer.write(end ?? glyph.verticalLine); + }, color: colors.BLUE); + } + + /// Returns the number of hard tabs in [text]. + int _countTabs(String text) { + var count = 0; + for (var char in text.codeUnits) { + if (char == $tab) count++; + } + return count; + } + + /// Returns whether [text] contains only space or tab characters. + bool _isOnlyWhitespace(String text) { + for (var char in text.codeUnits) { + if (char != $space && char != $tab) return false; + } + return true; + } + + /// Colors all text written to [_buffer] during [callback], if colorization is + /// enabled. + /// + /// If [color] is passed, it's used as the color; otherwise, [_color] is used. + void _colorize(void callback(), {String color}) { + if (_color != null) _buffer.write(color ?? _color); + callback(); + if (_color != null) _buffer.write(colors.NONE); + } +} diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index 19655a54a..57ffe79cb 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -2,6 +2,8 @@ // 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 'location.dart'; import 'span_mixin.dart'; @@ -54,6 +56,10 @@ abstract class SourceSpan implements Comparable { /// color red). 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. + /// + /// This uses the full range of Unicode characters to highlight the source + /// span if [glyph.ascii] is `false` (the default), but only uses ASCII + /// characters if it's `true`. String message(String message, {color}); /// Prints the text associated with this span in a user-friendly way. @@ -69,6 +75,10 @@ abstract class SourceSpan implements Comparable { /// color red). 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. + /// + /// This uses the full range of Unicode characters to highlight the source + /// span if [glyph.ascii] is `false` (the default), but only uses ASCII + /// characters if it's `true`. String highlight({color}); } diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index 1f7799d67..d8ac8f2ba 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -2,12 +2,9 @@ // 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 'dart:math' as math; - -import 'package:charcode/charcode.dart'; import 'package:path/path.dart' as p; -import 'colors.dart' as colors; +import 'highlighter.dart'; import 'span.dart'; import 'span_with_context.dart'; import 'utils.dart'; @@ -63,54 +60,8 @@ abstract class SourceSpanMixin implements SourceSpan { } String highlight({color}) { - if (color == true) color = colors.RED; - if (color == false) color = null; - - var column = start.column; - var buffer = new StringBuffer(); - String textLine; - if (this is SourceSpanWithContext) { - var context = (this as SourceSpanWithContext).context; - var lineStart = findLineStart(context, text, column); - if (lineStart != null && lineStart > 0) { - buffer.write(context.substring(0, lineStart)); - context = context.substring(lineStart); - } - var endIndex = context.indexOf('\n'); - textLine = endIndex == -1 ? context : context.substring(0, endIndex + 1); - column = math.min(column, textLine.length); - } else if (length == 0) { - return ""; - } else { - textLine = text.split("\n").first; - column = 0; - } - - var toColumn = - math.min(column + end.offset - start.offset, textLine.length); - if (color != null) { - buffer.write(textLine.substring(0, column)); - buffer.write(color); - buffer.write(textLine.substring(column, toColumn)); - buffer.write(colors.NONE); - buffer.write(textLine.substring(toColumn)); - } else { - buffer.write(textLine); - } - if (!textLine.endsWith('\n')) buffer.write('\n'); - - for (var i = 0; i < column; i++) { - if (textLine.codeUnitAt(i) == $tab) { - buffer.writeCharCode($tab); - } else { - buffer.writeCharCode($space); - } - } - - if (color != null) buffer.write(color); - buffer.write('^' * math.max(toColumn - column, 1)); - if (color != null) buffer.write(colors.NONE); - return buffer.toString(); + if (this is! SourceSpanWithContext && this.length == 0) return ""; + return new Highlighter(this, color: color).highlight(); } bool operator ==(other) => diff --git a/pkgs/source_span/lib/src/utils.dart b/pkgs/source_span/lib/src/utils.dart index 69385476c..228b240e0 100644 --- a/pkgs/source_span/lib/src/utils.dart +++ b/pkgs/source_span/lib/src/utils.dart @@ -12,19 +12,43 @@ Comparable min(Comparable obj1, Comparable obj2) => Comparable max(Comparable obj1, Comparable obj2) => obj1.compareTo(obj2) > 0 ? obj1 : obj2; +/// Returns the number of instances of [codeUnit] in [string]. +int countCodeUnits(String string, int codeUnit) { + var count = 0; + for (var codeUnitToCheck in string.codeUnits) { + if (codeUnitToCheck == codeUnit) count++; + } + return count; +} + /// Finds a line in [context] containing [text] at the specified [column]. /// /// Returns the index in [context] where that line begins, or null if none /// exists. int findLineStart(String context, String text, int column) { - var isEmpty = text == ''; + // If the text is empty, we just want to find the first line that has at least + // [column] characters. + if (text.isEmpty) { + var beginningOfLine = 0; + while (true) { + var index = context.indexOf("\n", beginningOfLine); + if (index == -1) { + return context.length - beginningOfLine >= column + ? beginningOfLine + : null; + } + + if (index - beginningOfLine >= column) return beginningOfLine; + beginningOfLine = index + 1; + } + } + var index = context.indexOf(text); while (index != -1) { - var lineStart = context.lastIndexOf('\n', 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; - if (column == textColumn || (isEmpty && column == textColumn + 1)) { - return lineStart; - } + if (column == textColumn) return lineStart; index = context.indexOf(text, index + 1); } return null; diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 1d5321007..ebd3a72a4 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.4.1 +version: 1.5.0 description: A library for identifying source spans and locations. author: Dart Team @@ -11,6 +11,7 @@ environment: dependencies: charcode: ^1.0.0 path: '>=1.2.0 <2.0.0' + term_glyph: ^1.0.0 dev_dependencies: test: '>=0.12.0 <2.0.0' diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index ac8334bd5..4eceaa823 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -3,10 +3,21 @@ // 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:source_span/src/colors.dart' as colors; main() { + bool oldAscii; + setUpAll(() { + oldAscii = glyph.ascii; + glyph.ascii = true; + }); + + tearDownAll(() { + glyph.ascii = oldAscii; + }); + var file; setUp(() { file = new SourceFile.fromString(""" @@ -18,101 +29,341 @@ zip zap zop test("points to the span in the source", () { expect(file.span(4, 7).highlight(), equals(""" -foo bar baz - ^^^""")); + , +1 | foo bar baz + | ^^^ + '""")); }); test("gracefully handles a missing source URL", () { var span = new SourceFile.fromString("foo bar baz").span(4, 7); expect(span.highlight(), equals(""" -foo bar baz - ^^^""")); - }); - - test("highlights the first line of a multiline span", () { - expect(file.span(4, 20).highlight(), equals(""" -foo bar baz - ^^^^^^^^""")); + , +1 | foo bar baz + | ^^^ + '""")); }); test("works for a point span", () { expect(file.location(4).pointSpan().highlight(), equals(""" -foo bar baz - ^""")); + , +1 | foo bar baz + | ^ + '""")); }); test("works for a point span at the end of a line", () { expect(file.location(11).pointSpan().highlight(), equals(""" -foo bar baz - ^""")); + , +1 | foo bar baz + | ^ + '""")); }); test("works for a point span at the end of the file", () { expect(file.location(38).pointSpan().highlight(), equals(""" -zip zap zop - ^""")); + , +3 | zip zap zop + | ^ + '""")); }); test("works for a point span at the end of the file with no trailing newline", () { file = new SourceFile.fromString("zip zap zop"); expect(file.location(11).pointSpan().highlight(), equals(""" -zip zap zop - ^""")); + , +1 | zip zap zop + | ^ + '""")); }); test("works for a point span in an empty file", () { expect(new SourceFile.fromString("").location(0).pointSpan().highlight(), equals(""" - -^""")); + , +1 | + | ^ + '""")); }); test("works for a single-line file without a newline", () { expect( new SourceFile.fromString("foo bar").span(0, 7).highlight(), equals(""" -foo bar -^^^^^^^""")); + , +1 | foo bar + | ^^^^^^^ + '""")); }); - test("emits tabs for tabs", () { - expect(new SourceFile.fromString(" \t \t\tfoo bar").span(5, 8).highlight(), - equals(""" - \t \t\tfoo bar - \t \t\t^^^""")); + group("with a multiline span", () { + test("highlights the middle of the first and last lines", () { + expect(file.span(4, 34).highlight(), equals(""" + , +1 | foo bar baz + | ,-----^ +2 | | whiz bang boom +3 | | zip zap zop + | '-------^ + '""")); + }); + + test("works when it begins at the end of a line", () { + expect(file.span(11, 34).highlight(), equals(""" + , +1 | foo bar baz + | ,------------^ +2 | | whiz bang boom +3 | | zip zap zop + | '-------^ + '""")); + }); + + test("works when it ends at the beginning of a line", () { + expect(file.span(4, 28).highlight(), equals(""" + , +1 | foo bar baz + | ,-----^ +2 | | whiz bang boom +3 | | zip zap zop + | '-^ + '""")); + }); + + test("highlights the full first line", () { + expect(file.span(0, 34).highlight(), equals(""" + , +1 | / foo bar baz +2 | | whiz bang boom +3 | | zip zap zop + | '-------^ + '""")); + }); + + test("highlights the full first line even if it's indented", () { + var file = new SourceFile.fromString(""" + foo bar baz + whiz bang boom + zip zap zop +"""); + + expect(file.span(2, 38).highlight(), equals(""" + , +1 | / foo bar baz +2 | | whiz bang boom +3 | | zip zap zop + | '-------^ + '""")); + }); + + test("highlights the full last line", () { + expect(file.span(4, 26).highlight(), equals(""" + , +1 | foo bar baz + | ,-----^ +2 | \\ whiz bang boom + '""")); + }); + + test("highlights the full last line at the end of the file", () { + expect(file.span(4, 39).highlight(), equals(""" + , +1 | foo bar baz + | ,-----^ +2 | | whiz bang boom +3 | \\ zip zap zop + '""")); + }); + + test("highlights the full last line with no trailing newline", () { + var file = new SourceFile.fromString(""" +foo bar baz +whiz bang boom +zip zap zop"""); + + expect(file.span(4, 38).highlight(), equals(""" + , +1 | foo bar baz + | ,-----^ +2 | | whiz bang boom +3 | \\ zip zap zop + '""")); + }); }); - test("supports lines of preceding context", () { + group("prints tabs as spaces", () { + group("in a single-line span", () { + test("before the highlighted section", () { + var span = new SourceFile.fromString("foo\tbar baz").span(4, 7); + + expect(span.highlight(), equals(""" + , +1 | foo bar baz + | ^^^ + '""")); + }); + + test("within the highlighted section", () { + var span = new SourceFile.fromString("foo bar\tbaz bang").span(4, 11); + + expect(span.highlight(), equals(""" + , +1 | foo bar baz bang + | ^^^^^^^^^^ + '""")); + }); + + test("after the highlighted section", () { + var span = new SourceFile.fromString("foo bar\tbaz").span(4, 7); + + expect(span.highlight(), equals(""" + , +1 | foo bar baz + | ^^^ + '""")); + }); + }); + + group("in a multi-line span", () { + test("before the highlighted section", () { + var span = new SourceFile.fromString(""" +foo\tbar baz +whiz bang boom +""").span(4, 21); + + expect(span.highlight(), equals(""" + , +1 | foo bar baz + | ,--------^ +2 | | whiz bang boom + | '---------^ + '""")); + }); + + test("within the first highlighted line", () { + var span = new SourceFile.fromString(""" +foo bar\tbaz +whiz bang boom +""").span(4, 21); + + expect(span.highlight(), equals(""" + , +1 | foo bar baz + | ,-----^ +2 | | whiz bang boom + | '---------^ + '""")); + }); + + test("within a middle highlighted line", () { + var span = new SourceFile.fromString(""" +foo bar baz +whiz\tbang boom +zip zap zop +""").span(4, 34); + + expect(span.highlight(), equals(""" + , +1 | foo bar baz + | ,-----^ +2 | | whiz bang boom +3 | | zip zap zop + | '-------^ + '""")); + }); + + test("within the last highlighted line", () { + var span = new SourceFile.fromString(""" +foo bar baz +whiz\tbang boom +""").span(4, 21); + + expect(span.highlight(), equals(""" + , +1 | foo bar baz + | ,-----^ +2 | | whiz bang boom + | '------------^ + '""")); + }); + + test("after the highlighted section", () { + var span = new SourceFile.fromString(""" +foo bar baz +whiz bang\tboom +""").span(4, 21); + + expect(span.highlight(), equals(""" + , +1 | foo bar baz + | ,-----^ +2 | | whiz bang boom + | '---------^ + '""")); + }); + }); + }); + + test("supports lines of preceding and following context", () { var span = new SourceSpanWithContext( - new SourceLocation(5, line: 3, column: 5, sourceUrl: "foo.dart"), - new SourceLocation(12, line: 3, column: 12, sourceUrl: "foo.dart"), + new SourceLocation(5, line: 2, column: 5, sourceUrl: "foo.dart"), + new SourceLocation(12, line: 2, column: 12, sourceUrl: "foo.dart"), "foo bar", "previous\nlines\n-----foo bar-----\nfollowing line\n"); expect(span.highlight(color: colors.YELLOW), equals(""" -previous -lines ------${colors.YELLOW}foo bar${colors.NONE}----- - ${colors.YELLOW}^^^^^^^${colors.NONE}""")); +${colors.BLUE} ,${colors.NONE} +${colors.BLUE}1 |${colors.NONE} previous +${colors.BLUE}2 |${colors.NONE} lines +${colors.BLUE}3 |${colors.NONE} -----${colors.YELLOW}foo bar${colors.NONE}----- +${colors.BLUE} |${colors.NONE} ${colors.YELLOW}^^^^^^^${colors.NONE} +${colors.BLUE}4 |${colors.NONE} following line +${colors.BLUE} '${colors.NONE}""")); }); group("colors", () { test("doesn't colorize if color is false", () { expect(file.span(4, 7).highlight(color: false), equals(""" -foo bar baz - ^^^""")); + , +1 | foo bar baz + | ^^^ + '""")); }); test("colorizes if color is true", () { expect(file.span(4, 7).highlight(color: true), equals(""" -foo ${colors.RED}bar${colors.NONE} baz - ${colors.RED}^^^${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(""" -foo ${colors.YELLOW}bar${colors.NONE} baz - ${colors.YELLOW}^^^${colors.NONE}""")); +${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}""")); + }); + + 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}""")); }); }); } diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart index b7637cf7c..99895162a 100644 --- a/pkgs/source_span/test/span_test.dart +++ b/pkgs/source_span/test/span_test.dart @@ -3,10 +3,22 @@ // BSD-style license that can be found in the LICENSE file. import 'package:test/test.dart'; +import 'package:term_glyph/term_glyph.dart' as glyph; + import 'package:source_span/source_span.dart'; import 'package:source_span/src/colors.dart' as colors; main() { + bool oldAscii; + setUpAll(() { + oldAscii = glyph.ascii; + glyph.ascii = true; + }); + + tearDownAll(() { + glyph.ascii = oldAscii; + }); + var span; setUp(() { span = new SourceSpan(new SourceLocation(5, sourceUrl: "foo.dart"), @@ -181,8 +193,10 @@ main() { test("prints the text being described", () { expect(span.message("oh no"), equals(""" line 1, column 6 of foo.dart: oh no -foo bar -^^^^^^^""")); + , +1 | foo bar + | ^^^^^^^ + '""")); }); test("gracefully handles a missing source URL", () { @@ -191,8 +205,10 @@ foo bar expect(span.message("oh no"), equalsIgnoringWhitespace(""" line 1, column 6: oh no -foo bar -^^^^^^^""")); + , +1 | foo bar + | ^^^^^^^ + '""")); }); test("gracefully handles empty text", () { @@ -205,22 +221,28 @@ foo bar test("doesn't colorize if color is false", () { expect(span.message("oh no", color: false), equals(""" line 1, column 6 of foo.dart: oh no -foo bar -^^^^^^^""")); + , +1 | foo bar + | ^^^^^^^ + '""")); }); test("colorizes if color is true", () { expect(span.message("oh no", color: true), equals(""" line 1, column 6 of foo.dart: oh no -${colors.RED}foo bar${colors.NONE} -${colors.RED}^^^^^^^${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(""" line 1, column 6 of foo.dart: oh no -${colors.YELLOW}foo bar${colors.NONE} -${colors.YELLOW}^^^^^^^${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", () { @@ -232,8 +254,10 @@ ${colors.YELLOW}^^^^^^^${colors.NONE}""")); expect(spanWithContext.message("oh no", color: colors.YELLOW), equals(""" line 1, column 6 of foo.dart: oh no ------${colors.YELLOW}foo bar${colors.NONE}----- - ${colors.YELLOW}^^^^^^^${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}""")); }); }); diff --git a/pkgs/source_span/test/utils_test.dart b/pkgs/source_span/test/utils_test.dart index 2a86cc070..a8146e33b 100644 --- a/pkgs/source_span/test/utils_test.dart +++ b/pkgs/source_span/test/utils_test.dart @@ -32,12 +32,23 @@ main() { expect(index, 4); }); + test('empty text in empty context', () { + var index = findLineStart('', '', 0); + expect(index, 0); + }); + test('found on the first line', () { var context = '0\n2\n45\n'; var 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); + expect(index, 0); + }); + test('not found', () { var context = '0\n2\n45\n'; var index = findLineStart(context, '0', 1); From 1073d5e97fee8416cf36e146f74a7814482d2430 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 20 Dec 2018 14:51:48 -0800 Subject: [PATCH 039/128] Add a missing import --- pkgs/source_span/test/highlight_test.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index 4eceaa823..19f8ca815 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -2,6 +2,7 @@ // 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'; import 'package:source_span/source_span.dart'; From 855d5ec02d98c0ca8c7a3a89817b87219681e544 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 26 Dec 2018 12:52:06 -0800 Subject: [PATCH 040/128] Code review --- pkgs/source_span/lib/src/highlighter.dart | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index bc0fe6981..a709d243a 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -44,6 +44,16 @@ class Highlighter { /// alignment. static const _spacesPerTab = 4; + /// Creats a [Highlighter] that will return a message associated with [span] + /// when [write] is called. + /// + /// [color] may either be a [String], a [bool], or `null`. If it's a string, + /// it indicates an [ANSI terminal color + /// escape](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) that should + /// be used to highlight the span's text (for example, `"\u001b[31m"` will + /// color red). 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. factory Highlighter(SourceSpan span, {color}) { if (color == true) color = colors.RED; if (color == false) color = null; @@ -114,8 +124,6 @@ class Highlighter { /// /// This method should only be called once. String highlight() { - //if (_span.length == 0 && _span.context.isEmpty) return ""; - _writeSidebar(end: glyph.downEnd); _buffer.writeln(); @@ -123,7 +131,7 @@ class Highlighter { // those first. var lineStart = findLineStart(_span.context, _span.text, _span.start.column); - assert(lineStart != null); // enfoced by [new Highlighter] + assert(lineStart != null); // enforced by [new Highlighter] var context = _span.context; if (lineStart > 0) { @@ -150,12 +158,13 @@ class Highlighter { if (lines.last.isEmpty && lines.length > 1) lines.removeLast(); _writeFirstLine(lines.first); + var lastLineIndex = _span.end.line - _span.start.line; if (_multiline) { _writeIntermediateLines( - lines.skip(1).take(_span.end.line - _span.start.line - 1)); - _writeLastLine(lines[_span.end.line - _span.start.line]); + lines.skip(1).take(lastLineIndex - 1)); + _writeLastLine(lines[lastLineIndex]); } - _writeTrailingLines(lines.skip(1 + _span.end.line - _span.start.line)); + _writeTrailingLines(lines.skip(lastLineIndex + 1)); _writeSidebar(end: glyph.upEnd); From 8aba87e8b2e939a532ff2f35614f3821ac830af7 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 10 Jan 2019 14:49:42 -0500 Subject: [PATCH 041/128] Format --- pkgs/source_span/lib/src/highlighter.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index a709d243a..17aa7b5f4 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -160,8 +160,7 @@ class Highlighter { _writeFirstLine(lines.first); var lastLineIndex = _span.end.line - _span.start.line; if (_multiline) { - _writeIntermediateLines( - lines.skip(1).take(lastLineIndex - 1)); + _writeIntermediateLines(lines.skip(1).take(lastLineIndex - 1)); _writeLastLine(lines[lastLineIndex]); } _writeTrailingLines(lines.skip(lastLineIndex + 1)); From 98b05ae788a8037becebd10c6da307bca20152a6 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 10 Jan 2019 14:50:14 -0500 Subject: [PATCH 042/128] More code review --- pkgs/source_span/lib/src/highlighter.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 17aa7b5f4..a05412a6f 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -127,8 +127,8 @@ class Highlighter { _writeSidebar(end: glyph.downEnd); _buffer.writeln(); - // If [context] contains lines prior to the one [text] appears on, write - // those first. + // If [_span.context] contains lines prior to the one [_span.text] appears + // on, write those first. var lineStart = findLineStart(_span.context, _span.text, _span.start.column); assert(lineStart != null); // enforced by [new Highlighter] From ecec3a2a2c11915613c08a745700573905d0570e Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 11 Jan 2019 17:07:30 -0800 Subject: [PATCH 043/128] Improve FileSpan.context Previously, if FileSpan.end was directly after a newline, FileSpan.context would include the entire next line in the span. Then when this span was highlighted, the end would point confusingly to the beginning of that next line. --- pkgs/source_span/CHANGELOG.md | 5 +++++ pkgs/source_span/lib/src/file.dart | 25 +++++++++++++++++++++-- pkgs/source_span/pubspec.yaml | 2 +- pkgs/source_span/test/highlight_test.dart | 13 +++++++++++- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 2248a3937..74ab342af 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.5.1 + +* Produce better source span highlights for multi-line spans that cover the + entire last line of the span, including the newline. + # 1.5.0 * Improve the output of `SourceSpan.highlight()` and `SourceSpan.message()`: diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 6154e1343..18c46e66c 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -291,8 +291,29 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { FileLocation get start => new FileLocation._(file, _start); FileLocation get end => new FileLocation._(file, _end); String get text => file.getText(_start, _end); - String get context => file.getText(file.getOffset(start.line), - end.line == file.lines - 1 ? null : file.getOffset(end.line + 1)); + + String get context { + var endLine = file.getLine(_end); + var endColumn = file.getColumn(_end); + + int endOffset; + if (endColumn == 0 && endLine != 0) { + // If [end] is at the very beginning of the line, the span covers the + // previous newline, so we only want to include the previous line in the + // context. + endOffset = _end; + } else if (endLine == file.lines - 1) { + // If the span covers the last line of the file, the context should go all + // the way to the end of the file. + endOffset = file.length; + } else { + // Otherwise, the context should cover the full line on which [end] + // appears. + endOffset = file.getOffset(endLine + 1); + } + + return file.getText(file.getOffset(file.getLine(_start)), endOffset); + } _FileSpan(this.file, this._start, this._end) { if (_end < _start) { diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index ebd3a72a4..fc5ba2b5b 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.5.0 +version: 1.5.1 description: A library for identifying source spans and locations. author: Dart Team diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index 19f8ca815..71b58c382 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -158,6 +158,15 @@ zip zap zop }); test("highlights the full last line", () { + expect(file.span(4, 27).highlight(), equals(""" + , +1 | foo bar baz + | ,-----^ +2 | \\ whiz bang boom + '""")); + }); + + test("highlights the full last line with no trailing newline", () { expect(file.span(4, 26).highlight(), equals(""" , 1 | foo bar baz @@ -176,7 +185,9 @@ zip zap zop '""")); }); - test("highlights the full last line with no trailing newline", () { + test( + "highlights the full last line at the end of the file with no trailing" + " newline", () { var file = new SourceFile.fromString(""" foo bar baz whiz bang boom From 219ded1bc95deb0fa6660971ff31118cf689a85f Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 11 Jan 2019 17:22:23 -0800 Subject: [PATCH 044/128] Make sure all full-line spans are highlighted properly Even if the context covers lines after the fully-covered line, the span shouldn't point to them. --- pkgs/source_span/lib/src/highlighter.dart | 16 ++++++ pkgs/source_span/test/highlight_test.dart | 66 +++++++++++++++++------ 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index a05412a6f..97d696d50 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -99,6 +99,22 @@ class Highlighter { newSpan = new SourceSpanWithContext(start, end, text, context); } + // Normalize [span] so that the end location is at the end of a line, rather + // than on the beginning of the next line. + if (newSpan.end.column == 0 && newSpan.end.line != newSpan.start.line) { + assert(newSpan.text.endsWith("\n")); + + var text = newSpan.text.substring(0, newSpan.text.length - 1); + newSpan = new SourceSpanWithContext( + newSpan.start, + new SourceLocation(span.end.offset - 1, + sourceUrl: span.sourceUrl, + line: span.end.line - 1, + column: _lastColumn(text)), + text, + newSpan.context); + } + return new Highlighter._(newSpan, color); } diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index 71b58c382..e2536ba10 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -316,21 +316,57 @@ whiz bang\tboom }); }); - test("supports lines of preceding and following context", () { - var span = new SourceSpanWithContext( - new SourceLocation(5, line: 2, column: 5, sourceUrl: "foo.dart"), - new SourceLocation(12, line: 2, column: 12, sourceUrl: "foo.dart"), - "foo bar", - "previous\nlines\n-----foo bar-----\nfollowing line\n"); - - expect(span.highlight(color: colors.YELLOW), equals(""" -${colors.BLUE} ,${colors.NONE} -${colors.BLUE}1 |${colors.NONE} previous -${colors.BLUE}2 |${colors.NONE} lines -${colors.BLUE}3 |${colors.NONE} -----${colors.YELLOW}foo bar${colors.NONE}----- -${colors.BLUE} |${colors.NONE} ${colors.YELLOW}^^^^^^^${colors.NONE} -${colors.BLUE}4 |${colors.NONE} following line -${colors.BLUE} '${colors.NONE}""")); + group("supports lines of preceding and following context for a span", () { + test("within a single line", () { + var span = new SourceSpanWithContext( + new SourceLocation(20, line: 2, column: 5, sourceUrl: "foo.dart"), + new SourceLocation(27, line: 2, column: 12, sourceUrl: "foo.dart"), + "foo bar", + "previous\nlines\n-----foo bar-----\nfollowing line\n"); + + expect(span.highlight(), equals(""" + , +1 | previous +2 | lines +3 | -----foo bar----- + | ^^^^^^^ +4 | following line + '""")); + }); + + test("covering a full line", () { + var span = new SourceSpanWithContext( + new SourceLocation(15, line: 2, column: 0, sourceUrl: "foo.dart"), + new SourceLocation(33, line: 3, column: 0, sourceUrl: "foo.dart"), + "-----foo bar-----\n", + "previous\nlines\n-----foo bar-----\nfollowing line\n"); + + expect(span.highlight(), equals(""" + , +1 | previous +2 | lines +3 | -----foo bar----- + | ^^^^^^^^^^^^^^^^^ +4 | following line + '""")); + }); + + test("covering multiple full lines", () { + var span = new SourceSpanWithContext( + new SourceLocation(15, line: 2, column: 0, sourceUrl: "foo.dart"), + new SourceLocation(23, line: 4, column: 0, sourceUrl: "foo.dart"), + "foo\nbar\n", + "previous\nlines\nfoo\nbar\nfollowing line\n"); + + expect(span.highlight(), equals(""" + , +1 | previous +2 | lines +3 | / foo +4 | \\ bar +5 | following line + '""")); + }); }); group("colors", () { From 8bb0c145ed5ed3734a40146b2378d50c4cebb59c Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 11 Jan 2019 18:05:30 -0800 Subject: [PATCH 045/128] Mark this as a dev version --- pkgs/source_span/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index fc5ba2b5b..13fa6481d 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.5.1 +version: 1.5.1-dev description: A library for identifying source spans and locations. author: Dart Team From dbe9b972ec57452513ea992fa60f082fdd739c90 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Sat, 12 Jan 2019 01:34:25 -0500 Subject: [PATCH 046/128] Refactor highlighter normalizations --- pkgs/source_span/lib/src/highlighter.dart | 119 ++++++++++++---------- 1 file changed, 64 insertions(+), 55 deletions(-) diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 97d696d50..62709128f 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -58,64 +58,73 @@ class Highlighter { if (color == true) color = colors.RED; if (color == false) color = null; - // Normalize [span] to ensure that it's a [SourceSpanWithContext] whose - // context actually contains its text at the expected column. If it's not, - // adjust the start and end locations' line and column fields so that the - // highlighter can assume they match up with the context. - SourceSpanWithContext newSpan; - if (span is SourceSpanWithContext && - findLineStart(span.context, span.text, span.start.column) != null) { - newSpan = span; - } else { - newSpan = new SourceSpanWithContext( - new SourceLocation(span.start.offset, - sourceUrl: span.sourceUrl, line: 0, column: 0), - new SourceLocation(span.end.offset, - sourceUrl: span.sourceUrl, - line: countCodeUnits(span.text, $lf), - column: _lastColumn(span.text)), - span.text, - span.text); - } + var newSpan = _normalizeContext(span); + newSpan = _normalizeTrailingNewline(newSpan); + newSpan = _normalizeEndOfLine(newSpan); - // Normalize [span] to remove a trailing newline from `span.context`. If - // necessary, also adjust `span.end` so that it doesn't point past where the - // trailing newline used to be. - if (newSpan.context.endsWith("\n")) { - var context = newSpan.context.substring(0, newSpan.context.length - 1); - - var text = newSpan.text; - var start = newSpan.start; - var end = newSpan.end; - if (newSpan.text.endsWith("\n") && _isTextAtEndOfContext(newSpan)) { - text = newSpan.text.substring(0, newSpan.text.length - 1); - end = new SourceLocation(newSpan.end.offset - 1, - sourceUrl: newSpan.sourceUrl, - line: newSpan.end.line - 1, - column: _lastColumn(text)); - start = - newSpan.start.offset == newSpan.end.offset ? end : newSpan.start; - } - newSpan = new SourceSpanWithContext(start, end, text, context); - } + return new Highlighter._(newSpan, color); + } - // Normalize [span] so that the end location is at the end of a line, rather - // than on the beginning of the next line. - if (newSpan.end.column == 0 && newSpan.end.line != newSpan.start.line) { - assert(newSpan.text.endsWith("\n")); - - var text = newSpan.text.substring(0, newSpan.text.length - 1); - newSpan = new SourceSpanWithContext( - newSpan.start, - new SourceLocation(span.end.offset - 1, - sourceUrl: span.sourceUrl, - line: span.end.line - 1, - column: _lastColumn(text)), - text, - newSpan.context); + /// Normalizes [span] to ensure that it's a [SourceSpanWithContext] whose + /// context actually contains its text at the expected column. + /// + /// If it's not already a [SourceSpanWithContext], adjust the start and end + /// locations' line and column fields so that the highlighter can assume they + /// match up with the context. + static SourceSpanWithContext _normalizeContext(SourceSpan span) => + span is SourceSpanWithContext && + findLineStart(span.context, span.text, span.start.column) != null + ? span + : new SourceSpanWithContext( + new SourceLocation(span.start.offset, + sourceUrl: span.sourceUrl, line: 0, column: 0), + new SourceLocation(span.end.offset, + sourceUrl: span.sourceUrl, + line: countCodeUnits(span.text, $lf), + column: _lastColumn(span.text)), + span.text, + span.text); + + /// Normalizes [span] to remove a trailing newline from `span.context`. + /// + /// If necessary, also adjust `span.end` so that it doesn't point past where + /// the trailing newline used to be. + static SourceSpanWithContext _normalizeTrailingNewline( + SourceSpanWithContext span) { + if (!span.context.endsWith("\n")) return span; + + var context = span.context.substring(0, span.context.length - 1); + var text = span.text; + var start = span.start; + var end = span.end; + if (span.text.endsWith("\n") && _isTextAtEndOfContext(span)) { + text = span.text.substring(0, span.text.length - 1); + end = new SourceLocation(span.end.offset - 1, + sourceUrl: span.sourceUrl, + line: span.end.line - 1, + column: _lastColumn(text)); + start = span.start.offset == span.end.offset ? end : span.start; } + return new SourceSpanWithContext(start, end, text, context); + } - return new Highlighter._(newSpan, color); + /// Normalizes [span] so that the end location is at the end of a line, rather + /// than on the beginning of the next line. + static SourceSpanWithContext _normalizeEndOfLine(SourceSpanWithContext span) { + if (span.end.column != 0) return span; + if (span.end.line == span.start.line) return span; + + assert(span.text.endsWith("\n")); + + var text = span.text.substring(0, span.text.length - 1); + return new SourceSpanWithContext( + span.start, + new SourceLocation(span.end.offset - 1, + sourceUrl: span.sourceUrl, + line: span.end.line - 1, + column: _lastColumn(text)), + text, + span.context); } /// Returns the (0-based) column number of the last column of the last line in [text]. @@ -147,7 +156,7 @@ class Highlighter { // on, write those first. var lineStart = findLineStart(_span.context, _span.text, _span.start.column); - assert(lineStart != null); // enforced by [new Highlighter] + assert(lineStart != null); // enforced by [_normalizeContext] var context = _span.context; if (lineStart > 0) { From d57354a31c779fef63b03ce760aabdc0455b1346 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Sat, 12 Jan 2019 02:17:15 -0500 Subject: [PATCH 047/128] Produce better highlights for Windows newlines --- pkgs/source_span/CHANGELOG.md | 3 +++ pkgs/source_span/lib/src/highlighter.dart | 24 +++++++++++++++++++++++ pkgs/source_span/pubspec.yaml | 2 +- pkgs/source_span/test/highlight_test.dart | 19 ++++++++++++++++-- 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 74ab342af..489f01a72 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -3,6 +3,9 @@ * Produce better source span highlights for multi-line spans that cover the entire last line of the span, including the newline. +* Produce better source span highlights for spans that contain Windows-style + newlines. + # 1.5.0 * Improve the output of `SourceSpan.highlight()` and `SourceSpan.message()`: diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 62709128f..3ed1749b8 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -59,6 +59,7 @@ class Highlighter { if (color == false) color = null; var newSpan = _normalizeContext(span); + newSpan = _normalizeNewlines(newSpan); newSpan = _normalizeTrailingNewline(newSpan); newSpan = _normalizeEndOfLine(newSpan); @@ -85,6 +86,29 @@ class Highlighter { span.text, span.text); + /// Normalizes [span] to replace Windows-style newlines with Unix-style + /// newlines. + static SourceSpanWithContext _normalizeNewlines(SourceSpanWithContext span) { + var text = span.text; + if (!text.contains("\r\n")) return span; + + var endOffset = span.end.offset; + for (var i = 0; i < text.length - 1; i++) { + if (text.codeUnitAt(i) == $cr && text.codeUnitAt(i + 1) == $lf) { + endOffset--; + } + } + + return new SourceSpanWithContext( + span.start, + new SourceLocation(endOffset, + sourceUrl: span.sourceUrl, + line: span.end.line, + column: span.end.column), + text.replaceAll("\r\n", "\n"), + span.context.replaceAll("\r\n", "\n")); + } + /// Normalizes [span] to remove a trailing newline from `span.context`. /// /// If necessary, also adjust `span.end` so that it doesn't point past where diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 13fa6481d..fc5ba2b5b 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.5.1-dev +version: 1.5.1 description: A library for identifying source spans and locations. author: Dart Team diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index e2536ba10..b9e7ded87 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -175,6 +175,21 @@ zip zap zop '""")); }); + test("highlights the full last line with a trailing Windows newline", () { + var file = new SourceFile.fromString(""" +foo bar baz\r +whiz bang boom\r +zip zap zop\r +"""); + + expect(file.span(4, 29).highlight(), equals(""" + , +1 | foo bar baz + | ,-----^ +2 | \\ whiz bang boom + '""")); + }); + test("highlights the full last line at the end of the file", () { expect(file.span(4, 39).highlight(), equals(""" , @@ -186,8 +201,8 @@ zip zap zop }); test( - "highlights the full last line at the end of the file with no trailing" - " newline", () { + "highlights the full last line at the end of the file with no trailing " + "newline", () { var file = new SourceFile.fromString(""" foo bar baz whiz bang boom From 1679e1f7f3ceab6f5c6f7ca6410b662c0b692a41 Mon Sep 17 00:00:00 2001 From: Evan Weible Date: Thu, 17 Jan 2019 14:07:13 -0700 Subject: [PATCH 048/128] SourceFile.span() should include last char when end offset omitted (dart-lang/source_span#28) --- pkgs/source_span/CHANGELOG.md | 6 ++++++ pkgs/source_span/lib/src/file.dart | 2 +- pkgs/source_span/pubspec.yaml | 2 +- pkgs/source_span/test/file_test.dart | 6 +++++- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 489f01a72..44c3ca5ed 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,9 @@ +# 1.5.2 + +* `SourceFile.span()` now goes to the end of the file by default, rather than + ending one character before the end of the file. This matches the documented + behavior. + # 1.5.1 * Produce better source span highlights for multi-line spans that cover the diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 18c46e66c..3941042f5 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -88,7 +88,7 @@ class SourceFile { /// /// If [end] isn't passed, it defaults to the end of the file. FileSpan span(int start, [int end]) { - if (end == null) end = length - 1; + if (end == null) end = length; return new _FileSpan(this, start, end); } diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index fc5ba2b5b..ffd9df32b 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.5.1 +version: 1.5.2-dev description: A library for identifying source spans and locations. author: Dart Team diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index 071f3f9d7..3f32a3cf5 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/test/file_test.dart @@ -157,7 +157,7 @@ zip zap zop""", url: "bar.dart").span(10, 11); test("end defaults to the end of the file", () { var span = file.span(5); expect(span.start, equals(file.location(5))); - expect(span.end, equals(file.location(file.length - 1))); + expect(span.end, equals(file.location(file.length))); }); }); @@ -253,6 +253,10 @@ zip zap zop""", url: "bar.dart").span(10, 11); expect(file.span(8, 15).text, equals("baz\nwhi")); }); + test("text includes the last char when end is defaulted to EOF", () { + expect(file.span(29).text, equals("p zap zop")); + }); + test("context contains the span's text", () { var span = file.span(8, 15); expect(span.context.contains(span.text), isTrue); From 6978f7eecbdbc70115442606f1daa478d3c9e914 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 17 Jan 2019 16:44:06 -0500 Subject: [PATCH 049/128] Make FileSpan.context include the full line for all point spans Previously, if a point span appeared at the beginning of a line or at the end of the last line of the file, FileSpan.context returned an empty string. --- pkgs/source_span/CHANGELOG.md | 3 +++ pkgs/source_span/lib/src/file.dart | 12 ++++++++- pkgs/source_span/test/file_test.dart | 40 +++++++++++++++++++++++++--- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 44c3ca5ed..67ba8d5d9 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -4,6 +4,9 @@ ending one character before the end of the file. This matches the documented behavior. +* `FileSpan.context` now includes the full line on which the span appears for + empty spans at the beginning and end of lines. + # 1.5.1 * Produce better source span highlights for multi-line spans that cover the diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 3941042f5..ec4db63bc 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -300,7 +300,17 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { if (endColumn == 0 && endLine != 0) { // If [end] is at the very beginning of the line, the span covers the // previous newline, so we only want to include the previous line in the - // context. + // context... + + if (length == 0) { + // ...unless this is a point span, in which case we want to include the + // next line (or the last line if this is the end of the file). + return endLine == file.lines - 1 + ? file.getText(file.getOffset(endLine - 1)) + : file.getText( + file.getOffset(endLine), file.getOffset(endLine + 1)); + } + endOffset = _end; } else if (endLine == file.lines - 1) { // If the span covers the last line of the file, the context should go all diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index 3f32a3cf5..117458d10 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/test/file_test.dart @@ -257,10 +257,42 @@ zip zap zop""", url: "bar.dart").span(10, 11); expect(file.span(29).text, equals("p zap zop")); }); - test("context contains the span's text", () { - var span = file.span(8, 15); - expect(span.context.contains(span.text), isTrue); - expect(span.context, equals('foo bar baz\nwhiz bang boom\n')); + group("context", () { + test("contains the span's text", () { + var 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); + 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); + expect(span.context, equals('whiz bang boom\n')); + }); + + group("contains the last line for a point span at the end of a file", () { + test("without a newline", () { + var span = file.span(file.length, file.length); + expect(span.context, equals('zip zap zop')); + }); + + test("with a newline", () { + file = new SourceFile.fromString(""" +foo bar baz +whiz bang boom +zip zap zop +""", url: "foo.dart"); + + var span = file.span(file.length, file.length); + expect(span.context, equals('zip zap zop\n')); + }); + }); }); group("union()", () { From 16c9fd3d523d76a008d1df768dfaaa832f0c0aa2 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 17 Jan 2019 17:09:13 -0500 Subject: [PATCH 050/128] Don't crash on spans that end on empty lines --- pkgs/source_span/CHANGELOG.md | 3 +++ pkgs/source_span/lib/src/highlighter.dart | 10 ++++---- pkgs/source_span/pubspec.yaml | 2 +- pkgs/source_span/test/highlight_test.dart | 28 +++++++++++++++++++++++ 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 67ba8d5d9..afba8b744 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -7,6 +7,9 @@ * `FileSpan.context` now includes the full line on which the span appears for empty spans at the beginning and end of lines. +* Fix an edge case where `FileSpan.highlight()` could crash when highlighting a + span that ended with an empty line. + # 1.5.1 * Produce better source span highlights for multi-line spans that cover the diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 3ed1749b8..f29a89d6d 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -202,12 +202,14 @@ class Highlighter { var lines = context.split("\n"); - // Trim a trailing newline so we don't add an empty line to the end of the - // highlight. - if (lines.last.isEmpty && lines.length > 1) lines.removeLast(); + var 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. + lines.removeLast(); + } _writeFirstLine(lines.first); - var lastLineIndex = _span.end.line - _span.start.line; if (_multiline) { _writeIntermediateLines(lines.skip(1).take(lastLineIndex - 1)); _writeLastLine(lines[lastLineIndex]); diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index ffd9df32b..fd80bc851 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.5.2-dev +version: 1.5.2 description: A library for identifying source spans and locations. author: Dart Team diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index b9e7ded87..8418367f7 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -154,6 +154,20 @@ zip zap zop 2 | | whiz bang boom 3 | | zip zap zop | '-------^ + '""")); + }); + + test("highlights the full last line if it's empty", () { + var file = new SourceFile.fromString(""" +foo + +bar +"""); + + expect(file.span(4, 9).highlight(), equals(""" + , +2 | / +3 | \\ bar '""")); }); @@ -214,6 +228,20 @@ zip zap zop"""); | ,-----^ 2 | | whiz bang boom 3 | \\ zip zap zop + '""")); + }); + + test("highlights the full last line if it's empty", () { + var file = new SourceFile.fromString(""" +foo + +bar +"""); + + expect(file.span(0, 5).highlight(), equals(""" + , +1 | / foo +2 | \\ '""")); }); }); From 4c07f419ea9dd14fc573f5efb34ced3d7e79f62e Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 23 Jan 2019 19:49:51 -0500 Subject: [PATCH 051/128] Fix a bug when highlighting an end-of-file point span (dart-lang/source_span#30) --- pkgs/source_span/CHANGELOG.md | 6 +++ pkgs/source_span/lib/src/highlighter.dart | 57 ++++++++++++++++------- pkgs/source_span/pubspec.yaml | 2 +- pkgs/source_span/test/highlight_test.dart | 29 +++++++++++- 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index afba8b744..6e79fbc46 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,9 @@ +# 1.5.3 + +* Fix an edge case where `FileSpan.highlight()` would put the highlight + indicator in the wrong position when highlighting a point span after the end + of a file. + # 1.5.2 * `SourceFile.span()` now goes to the end of the file by default, rather than diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index f29a89d6d..8100f1839 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -82,7 +82,7 @@ class Highlighter { new SourceLocation(span.end.offset, sourceUrl: span.sourceUrl, line: countCodeUnits(span.text, $lf), - column: _lastColumn(span.text)), + column: _lastLineLength(span.text)), span.text, span.text); @@ -126,34 +126,55 @@ class Highlighter { end = new SourceLocation(span.end.offset - 1, sourceUrl: span.sourceUrl, line: span.end.line - 1, - column: _lastColumn(text)); + column: _lastLineLength(text)); start = span.start.offset == span.end.offset ? end : span.start; } return new SourceSpanWithContext(start, end, text, context); } - /// Normalizes [span] so that the end location is at the end of a line, rather - /// than on the beginning of the next line. + /// Normalizes [span] so that the end location is at the end of a line rather + /// than at the beginning of the next line. static SourceSpanWithContext _normalizeEndOfLine(SourceSpanWithContext span) { if (span.end.column != 0) return span; - if (span.end.line == span.start.line) return span; - assert(span.text.endsWith("\n")); + if (span.length == 0) { + if (span.end.offset == 0) return span; - var text = span.text.substring(0, span.text.length - 1); - return new SourceSpanWithContext( - span.start, - new SourceLocation(span.end.offset - 1, - sourceUrl: span.sourceUrl, - line: span.end.line - 1, - column: _lastColumn(text)), - text, - span.context); + // If [span] is a point span with an empty context, there's no useful + // adjustment we can do. + if (span.context.isEmpty) return span; + + var location = new SourceLocation(span.end.offset - 1, + sourceUrl: span.sourceUrl, + line: span.end.line - 1, + column: _lastLineLength(span.context)); + return new SourceSpanWithContext(location, location, "", span.context); + } else { + if (span.end.line == span.start.line) return span; + + var text = span.text.substring(0, span.text.length - 1); + + return new SourceSpanWithContext( + span.start, + new SourceLocation(span.end.offset - 1, + sourceUrl: span.sourceUrl, + line: span.end.line - 1, + column: _lastLineLength(text)), + text, + span.context); + } } - /// Returns the (0-based) column number of the last column of the last line in [text]. - static int _lastColumn(String text) => - text.length - text.lastIndexOf("\n") + 1; + /// Returns the length of the last line in [text], whether or not it ends in a + /// newline. + static int _lastLineLength(String text) { + if (text.isEmpty) return 0; + + // The "- 1" here avoids counting the newline itself. + return text.codeUnitAt(text.length - 1) == $lf + ? text.length - text.lastIndexOf("\n", text.length - 2) - 1 + : text.length - text.lastIndexOf("\n") - 1; + } /// Returns whether [span]'s text runs all the way to the end of its context. static bool _isTextAtEndOfContext(SourceSpanWithContext span) => diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index fd80bc851..c4b4ccfdc 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.5.2 +version: 1.5.3 description: A library for identifying source spans and locations. author: Dart Team diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index 8418367f7..7832e5106 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -53,6 +53,14 @@ zip zap zop '""")); }); + test("works for a point span at the beginning of the file", () { + expect(file.location(0).pointSpan().highlight(), equals(""" + , +1 | foo bar baz + | ^ + '""")); + }); + test("works for a point span at the end of a line", () { expect(file.location(11).pointSpan().highlight(), equals(""" , @@ -69,9 +77,28 @@ zip zap zop '""")); }); + test("works for a point span after the end of the file", () { + expect(file.location(39).pointSpan().highlight(), equals(""" + , +3 | zip zap zop + | ^ + '""")); + }); + test("works for a point span at the end of the file with no trailing newline", () { file = new SourceFile.fromString("zip zap zop"); + expect(file.location(10).pointSpan().highlight(), equals(""" + , +1 | zip zap zop + | ^ + '""")); + }); + + test( + "works for a point span after the end of the file with no trailing newline", + () { + file = new SourceFile.fromString("zip zap zop"); expect(file.location(11).pointSpan().highlight(), equals(""" , 1 | zip zap zop @@ -157,7 +184,7 @@ zip zap zop '""")); }); - test("highlights the full last line if it's empty", () { + test("highlights the full first line if it's empty", () { var file = new SourceFile.fromString(""" foo From 96e3b6e3c578e2b5007572eaa6886eb3ed70a1ad Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Mon, 28 Jan 2019 19:01:23 -0500 Subject: [PATCH 052/128] Drop special support for point spans at the end of files (dart-lang/source_span#31) Drop special support for point spans at the end of files This broke point spans at the beginning of lines elsewhere in the file. Unfortunately, there's no way to disambiguate these currently. SourceSpanWithContext doesn't have any information about where the span appears in the context, so for point spans at column 0, it could be at the beginning of the line or after the trailing newline. We should eventually add something like SourceSpanWithContext.indexInContext, but that'll require a breaking release, since downstream users implement FileSpan as an interface. --- pkgs/source_span/CHANGELOG.md | 5 ++ pkgs/source_span/lib/src/file.dart | 4 +- pkgs/source_span/lib/src/highlighter.dart | 35 ++++------- pkgs/source_span/pubspec.yaml | 2 +- pkgs/source_span/test/file_test.dart | 8 +-- pkgs/source_span/test/highlight_test.dart | 71 +++++++++++++---------- 6 files changed, 61 insertions(+), 64 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 6e79fbc46..a07a0e6b4 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.5.4 + +* `FileSpan.highlight()` now properly highlights point spans at the beginning of + lines. + # 1.5.3 * Fix an edge case where `FileSpan.highlight()` would put the highlight diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index ec4db63bc..27dae5db2 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -304,9 +304,9 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { if (length == 0) { // ...unless this is a point span, in which case we want to include the - // next line (or the last line if this is the end of the file). + // next line (or the empty string if this is the end of the file). return endLine == file.lines - 1 - ? file.getText(file.getOffset(endLine - 1)) + ? "" : file.getText( file.getOffset(endLine), file.getOffset(endLine + 1)); } diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 8100f1839..8a928b3f3 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -136,33 +136,18 @@ class Highlighter { /// than at the beginning of the next line. static SourceSpanWithContext _normalizeEndOfLine(SourceSpanWithContext span) { if (span.end.column != 0) return span; + if (span.end.line == span.start.line) return span; - if (span.length == 0) { - if (span.end.offset == 0) return span; + var text = span.text.substring(0, span.text.length - 1); - // If [span] is a point span with an empty context, there's no useful - // adjustment we can do. - if (span.context.isEmpty) return span; - - var location = new SourceLocation(span.end.offset - 1, - sourceUrl: span.sourceUrl, - line: span.end.line - 1, - column: _lastLineLength(span.context)); - return new SourceSpanWithContext(location, location, "", span.context); - } else { - if (span.end.line == span.start.line) return span; - - var text = span.text.substring(0, span.text.length - 1); - - return new SourceSpanWithContext( - span.start, - new SourceLocation(span.end.offset - 1, - sourceUrl: span.sourceUrl, - line: span.end.line - 1, - column: _lastLineLength(text)), - text, - span.context); - } + return new SourceSpanWithContext( + span.start, + new SourceLocation(span.end.offset - 1, + sourceUrl: span.sourceUrl, + line: span.end.line - 1, + column: _lastLineLength(text)), + text, + span.context); } /// Returns the length of the last line in [text], whether or not it ends in a diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index c4b4ccfdc..a47087561 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.5.3 +version: 1.5.4 description: A library for identifying source spans and locations. author: Dart Team diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index 117458d10..e043ac3ae 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/test/file_test.dart @@ -276,13 +276,13 @@ zip zap zop""", url: "bar.dart").span(10, 11); expect(span.context, equals('whiz bang boom\n')); }); - group("contains the last line for a point span at the end of a file", () { - test("without a newline", () { + 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); expect(span.context, equals('zip zap zop')); }); - test("with a newline", () { + test("with a newline, contains an empty line", () { file = new SourceFile.fromString(""" foo bar baz whiz bang boom @@ -290,7 +290,7 @@ zip zap zop """, url: "foo.dart"); var span = file.span(file.length, file.length); - expect(span.context, equals('zip zap zop\n')); + expect(span.context, isEmpty); }); }); }); diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index 7832e5106..af9cd1ba0 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -45,77 +45,84 @@ zip zap zop '""")); }); - test("works for a point span", () { - expect(file.location(4).pointSpan().highlight(), equals(""" + group("highlights a point span", () { + test("in the middle of a line", () { + expect(file.location(4).pointSpan().highlight(), equals(""" , 1 | foo bar baz | ^ '""")); - }); + }); - test("works for a point span at the beginning of the file", () { - expect(file.location(0).pointSpan().highlight(), equals(""" + test("at the beginning of the file", () { + expect(file.location(0).pointSpan().highlight(), equals(""" , 1 | foo bar baz | ^ '""")); - }); + }); + + test("at the beginning of a line", () { + expect(file.location(12).pointSpan().highlight(), equals(""" + , +2 | whiz bang boom + | ^ + '""")); + }); - test("works for a point span at the end of a line", () { - expect(file.location(11).pointSpan().highlight(), equals(""" + test("at the end of a line", () { + expect(file.location(11).pointSpan().highlight(), equals(""" , 1 | foo bar baz | ^ '""")); - }); + }); - test("works for a point span at the end of the file", () { - expect(file.location(38).pointSpan().highlight(), equals(""" + test("at the end of the file", () { + expect(file.location(38).pointSpan().highlight(), equals(""" , 3 | zip zap zop | ^ '""")); - }); + }); - test("works for a point span after the end of the file", () { - expect(file.location(39).pointSpan().highlight(), equals(""" + test("after the end of the file", () { + expect(file.location(39).pointSpan().highlight(), equals(""" , -3 | zip zap zop - | ^ +4 | + | ^ '""")); - }); + }); - test("works for a point span at the end of the file with no trailing newline", - () { - file = new SourceFile.fromString("zip zap zop"); - expect(file.location(10).pointSpan().highlight(), equals(""" + test("at the end of the file with no trailing newline", () { + file = new SourceFile.fromString("zip zap zop"); + expect(file.location(10).pointSpan().highlight(), equals(""" , 1 | zip zap zop | ^ '""")); - }); + }); - test( - "works for a point span after the end of the file with no trailing newline", - () { - file = new SourceFile.fromString("zip zap zop"); - expect(file.location(11).pointSpan().highlight(), equals(""" + test("after the end of the file with no trailing newline", () { + file = new SourceFile.fromString("zip zap zop"); + expect(file.location(11).pointSpan().highlight(), equals(""" , 1 | zip zap zop | ^ '""")); - }); + }); - test("works for a point span in an empty file", () { - expect(new SourceFile.fromString("").location(0).pointSpan().highlight(), - equals(""" + test("in an empty file", () { + expect(new SourceFile.fromString("").location(0).pointSpan().highlight(), + equals(""" , 1 | | ^ '""")); + }); }); - test("works for a single-line file without a newline", () { + test("highlights a single-line file without a newline", () { expect( new SourceFile.fromString("foo bar").span(0, 7).highlight(), equals(""" , From e75afeaf7cd16e5e588d76af8413f9bc8d667e70 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 28 Feb 2019 14:30:54 -0800 Subject: [PATCH 053/128] Fix a highlighting bug (dart-lang/source_span#33) If a span covered a trailing newline and a single additional line, it went down a code path that resulted in a range error. That code path has now been fixed. Closes dart-lang/source_span#32 --- pkgs/source_span/CHANGELOG.md | 5 +++ pkgs/source_span/lib/src/highlighter.dart | 14 ++++++-- pkgs/source_span/pubspec.yaml | 2 +- pkgs/source_span/test/highlight_test.dart | 39 +++++++++++++++++++++++ 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index a07a0e6b4..ddb4ff05a 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.5.5 + +* Fix a bug where `FileSpan.highlight()` would crash for spans that covered a + trailing newline and a single additional empty line. + # 1.5.4 * `FileSpan.highlight()` now properly highlights point spans at the beginning of diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 8a928b3f3..17a47bcea 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -117,6 +117,10 @@ class Highlighter { SourceSpanWithContext span) { if (!span.context.endsWith("\n")) return span; + // If there's a full blank line on the end of [span.context], it's probably + // 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); var text = span.text; var start = span.start; @@ -156,9 +160,13 @@ class Highlighter { if (text.isEmpty) return 0; // The "- 1" here avoids counting the newline itself. - return text.codeUnitAt(text.length - 1) == $lf - ? text.length - text.lastIndexOf("\n", text.length - 2) - 1 - : text.length - text.lastIndexOf("\n") - 1; + if (text.codeUnitAt(text.length - 1) == $lf) { + return text.length == 1 + ? 0 + : text.length - text.lastIndexOf("\n", text.length - 2) - 1; + } else { + return text.length - text.lastIndexOf("\n") - 1; + } } /// Returns whether [span]'s text runs all the way to the end of its context. diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index a47087561..0cb932656 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.5.4 +version: 1.5.5 description: A library for identifying source spans and locations. author: Dart Team diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index af9cd1ba0..5fdf622f4 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -117,6 +117,15 @@ zip zap zop equals(""" , 1 | + | ^ + '""")); + }); + + test("on an empty line", () { + var file = new SourceFile.fromString("foo\n\nbar"); + expect(file.location(4).pointSpan().highlight(), equals(""" + , +2 | | ^ '""")); }); @@ -131,6 +140,15 @@ zip zap zop '""")); }); + test("highlights a single empty line", () { + expect(new SourceFile.fromString("foo\n\nbar").span(4, 5).highlight(), + equals(""" + , +2 | + | ^ + '""")); + }); + group("with a multiline span", () { test("highlights the middle of the first and last lines", () { expect(file.span(4, 34).highlight(), equals(""" @@ -275,6 +293,27 @@ bar expect(file.span(0, 5).highlight(), equals(""" , 1 | / foo +2 | \\ + '""")); + }); + + test("highlights multiple empty lines", () { + var file = new SourceFile.fromString("foo\n\n\n\nbar"); + expect(file.span(4, 7).highlight(), equals(""" + , +2 | / +3 | | +4 | \\ + '""")); + }); + + // Regression test for #32 + test("highlights the end of a line and an empty line", () { + var file = new SourceFile.fromString("foo\n\n"); + expect(file.span(3, 5).highlight(), equals(""" + , +1 | foo + | ,----^ 2 | \\ '""")); }); From 8d99f34578a2643de285d7926a37a9e8bb8587bb Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Fri, 26 Apr 2019 13:44:20 -0700 Subject: [PATCH 054/128] travis: test on the oldest supported SDK (dart-lang/source_span#34) --- pkgs/source_span/.travis.yml | 2 +- pkgs/source_span/pubspec.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkgs/source_span/.travis.yml b/pkgs/source_span/.travis.yml index 44a054287..18267fca2 100644 --- a/pkgs/source_span/.travis.yml +++ b/pkgs/source_span/.travis.yml @@ -2,7 +2,7 @@ language: dart dart: - dev - - stable + - 2.0.0 dart_task: - test: --platform vm,chrome diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 0cb932656..813dd3b2a 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,12 +1,12 @@ name: source_span -version: 1.5.5 +version: 1.5.6-dev description: A library for identifying source spans and locations. author: Dart Team homepage: https://github.com/dart-lang/source_span environment: - sdk: '>=1.8.0 <3.0.0' + sdk: '>=2.0.0 <3.0.0' dependencies: charcode: ^1.0.0 @@ -14,4 +14,4 @@ dependencies: term_glyph: ^1.0.0 dev_dependencies: - test: '>=0.12.0 <2.0.0' + test: ^1.0.0 From 77329f5d456e0692506c1bcca3faeb2d50405ec9 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 31 Jul 2019 21:12:34 -0700 Subject: [PATCH 055/128] Delete codereview.settings --- pkgs/source_span/codereview.settings | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 pkgs/source_span/codereview.settings diff --git a/pkgs/source_span/codereview.settings b/pkgs/source_span/codereview.settings deleted file mode 100644 index 6cae815a0..000000000 --- a/pkgs/source_span/codereview.settings +++ /dev/null @@ -1,3 +0,0 @@ -CODE_REVIEW_SERVER: http://codereview.chromium.org/ -VIEW_VC: https://github.com/dart-lang/source_span/commit/ -CC_LIST: reviews@dartlang.org \ No newline at end of file From a7bc53e81c8ada625bc6cba892eaeade0e79ff87 Mon Sep 17 00:00:00 2001 From: Jennifer Thakar Date: Fri, 6 Sep 2019 14:40:32 -0700 Subject: [PATCH 056/128] Fix padding around certain line numbers Resolves dart-lang/source_span#38. --- pkgs/source_span/CHANGELOG.md | 5 +++++ pkgs/source_span/lib/src/highlighter.dart | 2 +- pkgs/source_span/test/highlight_test.dart | 26 +++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index ddb4ff05a..0dfe483b6 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.5.6 + +* Fix padding around line numbers that are powers of 10 in + `FileSpan.highlight()`. + # 1.5.5 * Fix a bug where `FileSpan.highlight()` would crash for spans that covered a diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 17a47bcea..0714acdb4 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -181,7 +181,7 @@ class Highlighter { // In a purely mathematical world, floor(log10(n)) would give the number of // digits in n, but floating point errors render that unreliable in // practice. - _paddingBeforeSidebar = _span.end.line.toString().length + 1; + _paddingBeforeSidebar = (_span.end.line + 1).toString().length + 1; /// Returns the highlighted span text. /// diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index 5fdf622f4..521f7484e 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -530,4 +530,30 @@ ${colors.BLUE}3 |${colors.NONE} ${colors.RED}\\ zip zap zop${colors.NONE} ${colors.BLUE} '${colors.NONE}""")); }); }); + + group("line numbers have appropriate padding", () { + test("with line number 9", () { + expect( + SourceFile.fromString("\n" * 8 + "foo bar baz\n") + .span(8, 11) + .highlight(), + equals(""" + , +9 | foo bar baz + | ^^^ + '""")); + }); + + test("with line number 10", () { + expect( + SourceFile.fromString("\n" * 9 + "foo bar baz\n") + .span(9, 12) + .highlight(), + equals(""" + , +10 | foo bar baz + | ^^^ + '""")); + }); + }); } From 34e1c6175626e4764c13358ffd190d508e6b7d7e Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Wed, 6 Nov 2019 17:15:02 -0800 Subject: [PATCH 057/128] Migrate off deprecated isInstanceOf (dart-lang/source_span#40) - Bump `package:test` to `1.6.0` which introduce `isA`. - Use `2.1.0` SDK on travis since it's the minimum supported by `test`. - Bump min SDK in the pubspec to `2.1.0` to match what is tested. - Replace `new isInstanceOf` with `isA`. --- pkgs/source_span/.travis.yml | 2 +- pkgs/source_span/pubspec.yaml | 4 ++-- pkgs/source_span/test/file_test.dart | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkgs/source_span/.travis.yml b/pkgs/source_span/.travis.yml index 18267fca2..ace10ab04 100644 --- a/pkgs/source_span/.travis.yml +++ b/pkgs/source_span/.travis.yml @@ -2,7 +2,7 @@ language: dart dart: - dev - - 2.0.0 + - 2.1.0 dart_task: - test: --platform vm,chrome diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 813dd3b2a..71e10f60a 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -6,7 +6,7 @@ author: Dart Team homepage: https://github.com/dart-lang/source_span environment: - sdk: '>=2.0.0 <3.0.0' + sdk: '>=2.1.0 <3.0.0' dependencies: charcode: ^1.0.0 @@ -14,4 +14,4 @@ dependencies: term_glyph: ^1.0.0 dev_dependencies: - test: ^1.0.0 + test: ^1.6.0 diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index e043ac3ae..9a103c4ae 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/test/file_test.dart @@ -241,7 +241,7 @@ zip zap zop""", url: "bar.dart").span(10, 11); test("pointSpan() returns a FileSpan", () { var location = file.location(15); var span = location.pointSpan(); - expect(span, new isInstanceOf()); + expect(span, isA()); expect(span.start, equals(location)); expect(span.end, equals(location)); expect(span.text, isEmpty); @@ -344,14 +344,14 @@ zip zap zop }); test("returns a FileSpan for a FileSpan input", () { - expect(span.union(file.span(0, 5)), new isInstanceOf()); + expect(span.union(file.span(0, 5)), isA()); }); test("returns a base SourceSpan for a SourceSpan input", () { var other = new SourceSpan(new SourceLocation(0, sourceUrl: "foo.dart"), new SourceLocation(5, sourceUrl: "foo.dart"), "hey, "); var result = span.union(other); - expect(result, isNot(new isInstanceOf())); + expect(result, isNot(isA())); expect(result.start, equals(other.start)); expect(result.end, equals(span.end)); expect(result.text, equals("hey, ar baz\n")); From 73c4d394b1de6d70b8cd4998b70b9a24c3457a86 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Thu, 7 Nov 2019 10:07:46 -0800 Subject: [PATCH 058/128] Run dartfmt --fix (dart-lang/source_span#42) Drops unnecessary `new`. --- pkgs/source_span/lib/src/file.dart | 56 +++---- pkgs/source_span/lib/src/highlighter.dart | 22 +-- pkgs/source_span/lib/src/location.dart | 12 +- pkgs/source_span/lib/src/location_mixin.dart | 6 +- pkgs/source_span/lib/src/span.dart | 8 +- pkgs/source_span/lib/src/span_mixin.dart | 10 +- .../lib/src/span_with_context.dart | 5 +- pkgs/source_span/test/file_test.dart | 17 +- pkgs/source_span/test/highlight_test.dart | 67 ++++---- pkgs/source_span/test/location_test.dart | 27 ++-- pkgs/source_span/test/span_test.dart | 152 ++++++++---------- 11 files changed, 183 insertions(+), 199 deletions(-) diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 27dae5db2..5a193d34d 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -72,7 +72,7 @@ class SourceFile { /// or equal to `0xFFFF`. SourceFile.decoded(Iterable decodedChars, {url}) : url = url is String ? Uri.parse(url) : url, - _decodedChars = new Uint32List.fromList(decodedChars.toList()) { + _decodedChars = Uint32List.fromList(decodedChars.toList()) { for (var i = 0; i < _decodedChars.length; i++) { var c = _decodedChars[i]; if (c == _CR) { @@ -89,18 +89,18 @@ class SourceFile { /// If [end] isn't passed, it defaults to the end of the file. FileSpan span(int start, [int end]) { if (end == null) end = length; - return new _FileSpan(this, start, end); + return _FileSpan(this, start, end); } /// Returns a location in [this] at [offset]. - FileLocation location(int offset) => new FileLocation._(this, offset); + FileLocation location(int offset) => FileLocation._(this, offset); /// Gets the 0-based line corresponding to [offset]. int getLine(int offset) { if (offset < 0) { - throw new RangeError("Offset may not be negative, was $offset."); + throw RangeError("Offset may not be negative, was $offset."); } else if (offset > length) { - throw new RangeError("Offset $offset must not be greater than the number " + throw RangeError("Offset $offset must not be greater than the number " "of characters in the file, $length."); } @@ -163,24 +163,24 @@ class SourceFile { /// is used to more efficiently compute the column. int getColumn(int offset, {int line}) { if (offset < 0) { - throw new RangeError("Offset may not be negative, was $offset."); + throw RangeError("Offset may not be negative, was $offset."); } else if (offset > length) { - throw new RangeError("Offset $offset must be not be greater than the " + throw RangeError("Offset $offset must be not be greater than the " "number of characters in the file, $length."); } if (line == null) { line = getLine(offset); } else if (line < 0) { - throw new RangeError("Line may not be negative, was $line."); + throw RangeError("Line may not be negative, was $line."); } else if (line >= lines) { - throw new RangeError("Line $line must be less than the number of " + throw RangeError("Line $line must be less than the number of " "lines in the file, $lines."); } var lineStart = _lineStarts[line]; if (lineStart > offset) { - throw new RangeError("Line $line comes after offset $offset."); + throw RangeError("Line $line comes after offset $offset."); } return offset - lineStart; @@ -193,18 +193,18 @@ class SourceFile { if (column == null) column = 0; if (line < 0) { - throw new RangeError("Line may not be negative, was $line."); + throw RangeError("Line may not be negative, was $line."); } else if (line >= lines) { - throw new RangeError("Line $line must be less than the number of " + throw RangeError("Line $line must be less than the number of " "lines in the file, $lines."); } else if (column < 0) { - throw new RangeError("Column may not be negative, was $column."); + throw RangeError("Column may not be negative, was $column."); } var result = _lineStarts[line] + column; if (result > length || (line + 1 < lines && result >= _lineStarts[line + 1])) { - throw new RangeError("Line $line doesn't have $column columns."); + throw RangeError("Line $line doesn't have $column columns."); } return result; @@ -214,7 +214,7 @@ class SourceFile { /// /// If [end] isn't passed, it defaults to the end of the file. String getText(int start, [int end]) => - new String.fromCharCodes(_decodedChars.sublist(start, end)); + String.fromCharCodes(_decodedChars.sublist(start, end)); } /// A [SourceLocation] within a [SourceFile]. @@ -234,14 +234,14 @@ class FileLocation extends SourceLocationMixin implements SourceLocation { FileLocation._(this.file, this.offset) { if (offset < 0) { - throw new RangeError("Offset may not be negative, was $offset."); + throw RangeError("Offset may not be negative, was $offset."); } else if (offset > file.length) { - throw new RangeError("Offset $offset must not be greater than the number " + throw RangeError("Offset $offset must not be greater than the number " "of characters in the file, ${file.length}."); } } - FileSpan pointSpan() => new _FileSpan(file, offset, offset); + FileSpan pointSpan() => _FileSpan(file, offset, offset); } /// A [SourceSpan] within a [SourceFile]. @@ -288,8 +288,8 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { Uri get sourceUrl => file.url; int get length => _end - _start; - FileLocation get start => new FileLocation._(file, _start); - FileLocation get end => new FileLocation._(file, _end); + FileLocation get start => FileLocation._(file, _start); + FileLocation get end => FileLocation._(file, _end); String get text => file.getText(_start, _end); String get context { @@ -327,12 +327,12 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { _FileSpan(this.file, this._start, this._end) { if (_end < _start) { - throw new ArgumentError('End $_end must come after start $_start.'); + throw ArgumentError('End $_end must come after start $_start.'); } else if (_end > file.length) { - throw new RangeError("End $_end must not be greater than the number " + throw RangeError("End $_end must not be greater than the number " "of characters in the file, ${file.length}."); } else if (_start < 0) { - throw new RangeError("Start may not be negative, was $_start."); + throw RangeError("Start may not be negative, was $_start."); } } @@ -351,11 +351,11 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { if (other is _FileSpan) { if (this._start > other._end || other._start > this._end) { - throw new ArgumentError("Spans $this and $other are disjoint."); + throw ArgumentError("Spans $this and $other are disjoint."); } } else { if (this._start > other.end.offset || other.start.offset > this._end) { - throw new ArgumentError("Spans $this and $other are disjoint."); + throw ArgumentError("Spans $this and $other are disjoint."); } } @@ -382,18 +382,18 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { /// between the two will be covered by the returned span. FileSpan expand(FileSpan other) { if (sourceUrl != other.sourceUrl) { - throw new 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); - return new _FileSpan(file, start, 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); - return new _FileSpan(file, start, end); + return _FileSpan(file, start, end); } } } diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 0714acdb4..f68e52a3e 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -36,7 +36,7 @@ class Highlighter { _multiline ? 3 : 1; /// The buffer to which to write the result. - final _buffer = new StringBuffer(); + final _buffer = StringBuffer(); /// The number of spaces to render for hard tabs that appear in `_span.text`. /// @@ -63,7 +63,7 @@ class Highlighter { newSpan = _normalizeTrailingNewline(newSpan); newSpan = _normalizeEndOfLine(newSpan); - return new Highlighter._(newSpan, color); + return Highlighter._(newSpan, color); } /// Normalizes [span] to ensure that it's a [SourceSpanWithContext] whose @@ -76,10 +76,10 @@ class Highlighter { span is SourceSpanWithContext && findLineStart(span.context, span.text, span.start.column) != null ? span - : new SourceSpanWithContext( - new SourceLocation(span.start.offset, + : SourceSpanWithContext( + SourceLocation(span.start.offset, sourceUrl: span.sourceUrl, line: 0, column: 0), - new SourceLocation(span.end.offset, + SourceLocation(span.end.offset, sourceUrl: span.sourceUrl, line: countCodeUnits(span.text, $lf), column: _lastLineLength(span.text)), @@ -99,9 +99,9 @@ class Highlighter { } } - return new SourceSpanWithContext( + return SourceSpanWithContext( span.start, - new SourceLocation(endOffset, + SourceLocation(endOffset, sourceUrl: span.sourceUrl, line: span.end.line, column: span.end.column), @@ -127,13 +127,13 @@ class Highlighter { var end = span.end; if (span.text.endsWith("\n") && _isTextAtEndOfContext(span)) { text = span.text.substring(0, span.text.length - 1); - end = new SourceLocation(span.end.offset - 1, + end = SourceLocation(span.end.offset - 1, sourceUrl: span.sourceUrl, line: span.end.line - 1, column: _lastLineLength(text)); start = span.start.offset == span.end.offset ? end : span.start; } - return new SourceSpanWithContext(start, end, text, context); + return SourceSpanWithContext(start, end, text, context); } /// Normalizes [span] so that the end location is at the end of a line rather @@ -144,9 +144,9 @@ class Highlighter { var text = span.text.substring(0, span.text.length - 1); - return new SourceSpanWithContext( + return SourceSpanWithContext( span.start, - new SourceLocation(span.end.offset - 1, + SourceLocation(span.end.offset - 1, sourceUrl: span.sourceUrl, line: span.end.line - 1, column: _lastLineLength(text)), diff --git a/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart index cf9931951..a27188046 100644 --- a/pkgs/source_span/lib/src/location.dart +++ b/pkgs/source_span/lib/src/location.dart @@ -48,11 +48,11 @@ class SourceLocation implements Comparable { line = line == null ? 0 : line, column = column == null ? offset : column { if (offset < 0) { - throw new RangeError("Offset may not be negative, was $offset."); + throw RangeError("Offset may not be negative, was $offset."); } else if (line != null && line < 0) { - throw new RangeError("Line may not be negative, was $line."); + throw RangeError("Line may not be negative, was $line."); } else if (column != null && column < 0) { - throw new RangeError("Column may not be negative, was $column."); + throw RangeError("Column may not be negative, was $column."); } } @@ -61,21 +61,21 @@ class SourceLocation implements Comparable { /// This always returns a non-negative value. int distance(SourceLocation other) { if (sourceUrl != other.sourceUrl) { - throw new ArgumentError("Source URLs \"${sourceUrl}\" and " + throw ArgumentError("Source URLs \"${sourceUrl}\" and " "\"${other.sourceUrl}\" don't match."); } return (offset - other.offset).abs(); } /// Returns a span that covers only a single point: this location. - SourceSpan pointSpan() => new SourceSpan(this, this, ""); + SourceSpan pointSpan() => SourceSpan(this, this, ""); /// Compares two locations. /// /// [other] must have the same source URL as [this]. int compareTo(SourceLocation other) { if (sourceUrl != other.sourceUrl) { - throw new ArgumentError("Source URLs \"${sourceUrl}\" and " + throw ArgumentError("Source URLs \"${sourceUrl}\" and " "\"${other.sourceUrl}\" don't match."); } return offset - other.offset; diff --git a/pkgs/source_span/lib/src/location_mixin.dart b/pkgs/source_span/lib/src/location_mixin.dart index 1e5fc66f8..7d34311fc 100644 --- a/pkgs/source_span/lib/src/location_mixin.dart +++ b/pkgs/source_span/lib/src/location_mixin.dart @@ -21,17 +21,17 @@ abstract class SourceLocationMixin implements SourceLocation { int distance(SourceLocation other) { if (sourceUrl != other.sourceUrl) { - throw new ArgumentError("Source URLs \"${sourceUrl}\" and " + throw ArgumentError("Source URLs \"${sourceUrl}\" and " "\"${other.sourceUrl}\" don't match."); } return (offset - other.offset).abs(); } - SourceSpan pointSpan() => new SourceSpan(this, this, ""); + SourceSpan pointSpan() => SourceSpan(this, this, ""); int compareTo(SourceLocation other) { if (sourceUrl != other.sourceUrl) { - throw new ArgumentError("Source URLs \"${sourceUrl}\" and " + throw ArgumentError("Source URLs \"${sourceUrl}\" and " "\"${other.sourceUrl}\" don't match."); } return offset - other.offset; diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index 57ffe79cb..b32e1ff6a 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -33,7 +33,7 @@ abstract class SourceSpan implements Comparable { /// before [end]. [text] must have a number of characters equal to the /// distance between [start] and [end]. factory SourceSpan(SourceLocation start, SourceLocation end, String text) => - new SourceSpanBase(start, end, text); + SourceSpanBase(start, end, text); /// Creates a new span that's the union of [this] and [other]. /// @@ -91,12 +91,12 @@ class SourceSpanBase extends SourceSpanMixin { SourceSpanBase(this.start, this.end, this.text) { if (end.sourceUrl != start.sourceUrl) { - throw new ArgumentError("Source URLs \"${start.sourceUrl}\" and " + throw ArgumentError("Source URLs \"${start.sourceUrl}\" and " " \"${end.sourceUrl}\" don't match."); } else if (end.offset < start.offset) { - throw new ArgumentError('End $end must come after start $start.'); + throw ArgumentError('End $end must come after start $start.'); } else if (text.length != start.distance(end)) { - throw new ArgumentError('Text "$text" must be ${start.distance(end)} ' + throw ArgumentError('Text "$text" must be ${start.distance(end)} ' 'characters long.'); } } diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index d8ac8f2ba..9bf0937ec 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -26,7 +26,7 @@ abstract class SourceSpanMixin implements SourceSpan { SourceSpan union(SourceSpan other) { if (sourceUrl != other.sourceUrl) { - throw new ArgumentError("Source URLs \"${sourceUrl}\" and " + throw ArgumentError("Source URLs \"${sourceUrl}\" and " " \"${other.sourceUrl}\" don't match."); } @@ -36,16 +36,16 @@ abstract class SourceSpanMixin implements SourceSpan { var endSpan = end == this.end ? this : other; if (beginSpan.end.compareTo(endSpan.start) < 0) { - throw new ArgumentError("Spans $this and $other are disjoint."); + throw ArgumentError("Spans $this and $other are disjoint."); } var text = beginSpan.text + endSpan.text.substring(beginSpan.end.distance(endSpan.start)); - return new SourceSpan(start, end, text); + return SourceSpan(start, end, text); } String message(String message, {color}) { - var buffer = new StringBuffer(); + var buffer = StringBuffer(); buffer.write('line ${start.line + 1}, column ${start.column + 1}'); if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}'); buffer.write(': $message'); @@ -61,7 +61,7 @@ abstract class SourceSpanMixin implements SourceSpan { String highlight({color}) { if (this is! SourceSpanWithContext && this.length == 0) return ""; - return new Highlighter(this, color: color).highlight(); + return Highlighter(this, color: color).highlight(); } bool operator ==(other) => diff --git a/pkgs/source_span/lib/src/span_with_context.dart b/pkgs/source_span/lib/src/span_with_context.dart index 41697a0a6..da09cc0b8 100644 --- a/pkgs/source_span/lib/src/span_with_context.dart +++ b/pkgs/source_span/lib/src/span_with_context.dart @@ -25,12 +25,11 @@ class SourceSpanWithContext extends SourceSpanBase { SourceLocation start, SourceLocation end, String text, this._context) : super(start, end, text) { if (!context.contains(text)) { - throw new ArgumentError( - 'The context line "$context" must contain "$text".'); + throw ArgumentError('The context line "$context" must contain "$text".'); } if (findLineStart(context, text, start.column) == null) { - throw new ArgumentError('The span text "$text" must start at ' + throw ArgumentError('The span text "$text" must start at ' 'column ${start.column + 1} in a line within "$context".'); } } diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index 9a103c4ae..6759ca257 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/test/file_test.dart @@ -8,7 +8,7 @@ import 'package:source_span/source_span.dart'; main() { var file; setUp(() { - file = new SourceFile.fromString(""" + file = SourceFile.fromString(""" foo bar baz whiz bang boom zip zap zop""", url: "foo.dart"); @@ -109,8 +109,7 @@ zip zap zop""", url: "foo.dart"); group("for span().union()", () { test("source URLs must match", () { - var other = - new SourceSpan(new SourceLocation(10), new SourceLocation(11), "_"); + var other = SourceSpan(SourceLocation(10), SourceLocation(11), "_"); expect(() => file.span(9, 10).union(other), throwsArgumentError); }); @@ -122,7 +121,7 @@ zip zap zop""", url: "foo.dart"); }); test("for span().expand() source URLs must match", () { - var other = new SourceFile.fromString(""" + var other = SourceFile.fromString(""" foo bar baz whiz bang boom zip zap zop""", url: "bar.dart").span(10, 11); @@ -139,11 +138,11 @@ zip zap zop""", url: "bar.dart").span(10, 11); group("new SourceFile()", () { test("handles CRLF correctly", () { - expect(new SourceFile.fromString("foo\r\nbar").getLine(6), equals(1)); + expect(SourceFile.fromString("foo\r\nbar").getLine(6), equals(1)); }); test("handles a lone CR correctly", () { - expect(new SourceFile.fromString("foo\rbar").getLine(5), equals(1)); + expect(SourceFile.fromString("foo\rbar").getLine(5), equals(1)); }); }); @@ -283,7 +282,7 @@ zip zap zop""", url: "bar.dart").span(10, 11); }); test("with a newline, contains an empty line", () { - file = new SourceFile.fromString(""" + file = SourceFile.fromString(""" foo bar baz whiz bang boom zip zap zop @@ -348,8 +347,8 @@ zip zap zop }); test("returns a base SourceSpan for a SourceSpan input", () { - var other = new SourceSpan(new SourceLocation(0, sourceUrl: "foo.dart"), - new SourceLocation(5, sourceUrl: "foo.dart"), "hey, "); + var other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"), + SourceLocation(5, sourceUrl: "foo.dart"), "hey, "); var result = span.union(other); expect(result, isNot(isA())); expect(result.start, equals(other.start)); diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index 521f7484e..c2156803c 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -21,7 +21,7 @@ main() { var file; setUp(() { - file = new SourceFile.fromString(""" + file = SourceFile.fromString(""" foo bar baz whiz bang boom zip zap zop @@ -37,7 +37,7 @@ zip zap zop }); test("gracefully handles a missing source URL", () { - var span = new SourceFile.fromString("foo bar baz").span(4, 7); + var span = SourceFile.fromString("foo bar baz").span(4, 7); expect(span.highlight(), equals(""" , 1 | foo bar baz @@ -95,7 +95,7 @@ zip zap zop }); test("at the end of the file with no trailing newline", () { - file = new SourceFile.fromString("zip zap zop"); + file = SourceFile.fromString("zip zap zop"); expect(file.location(10).pointSpan().highlight(), equals(""" , 1 | zip zap zop @@ -104,7 +104,7 @@ zip zap zop }); test("after the end of the file with no trailing newline", () { - file = new SourceFile.fromString("zip zap zop"); + file = SourceFile.fromString("zip zap zop"); expect(file.location(11).pointSpan().highlight(), equals(""" , 1 | zip zap zop @@ -113,7 +113,7 @@ zip zap zop }); test("in an empty file", () { - expect(new SourceFile.fromString("").location(0).pointSpan().highlight(), + expect(SourceFile.fromString("").location(0).pointSpan().highlight(), equals(""" , 1 | @@ -122,7 +122,7 @@ zip zap zop }); test("on an empty line", () { - var file = new SourceFile.fromString("foo\n\nbar"); + var file = SourceFile.fromString("foo\n\nbar"); expect(file.location(4).pointSpan().highlight(), equals(""" , 2 | @@ -132,8 +132,7 @@ zip zap zop }); test("highlights a single-line file without a newline", () { - expect( - new SourceFile.fromString("foo bar").span(0, 7).highlight(), equals(""" + expect(SourceFile.fromString("foo bar").span(0, 7).highlight(), equals(""" , 1 | foo bar | ^^^^^^^ @@ -141,8 +140,8 @@ zip zap zop }); test("highlights a single empty line", () { - expect(new SourceFile.fromString("foo\n\nbar").span(4, 5).highlight(), - equals(""" + expect( + SourceFile.fromString("foo\n\nbar").span(4, 5).highlight(), equals(""" , 2 | | ^ @@ -194,7 +193,7 @@ zip zap zop }); test("highlights the full first line even if it's indented", () { - var file = new SourceFile.fromString(""" + var file = SourceFile.fromString(""" foo bar baz whiz bang boom zip zap zop @@ -210,7 +209,7 @@ zip zap zop }); test("highlights the full first line if it's empty", () { - var file = new SourceFile.fromString(""" + var file = SourceFile.fromString(""" foo bar @@ -242,7 +241,7 @@ bar }); test("highlights the full last line with a trailing Windows newline", () { - var file = new SourceFile.fromString(""" + var file = SourceFile.fromString(""" foo bar baz\r whiz bang boom\r zip zap zop\r @@ -269,7 +268,7 @@ zip zap zop\r test( "highlights the full last line at the end of the file with no trailing " "newline", () { - var file = new SourceFile.fromString(""" + var file = SourceFile.fromString(""" foo bar baz whiz bang boom zip zap zop"""); @@ -284,7 +283,7 @@ zip zap zop"""); }); test("highlights the full last line if it's empty", () { - var file = new SourceFile.fromString(""" + var file = SourceFile.fromString(""" foo bar @@ -298,7 +297,7 @@ bar }); test("highlights multiple empty lines", () { - var file = new SourceFile.fromString("foo\n\n\n\nbar"); + var file = SourceFile.fromString("foo\n\n\n\nbar"); expect(file.span(4, 7).highlight(), equals(""" , 2 | / @@ -309,7 +308,7 @@ bar // Regression test for #32 test("highlights the end of a line and an empty line", () { - var file = new SourceFile.fromString("foo\n\n"); + var file = SourceFile.fromString("foo\n\n"); expect(file.span(3, 5).highlight(), equals(""" , 1 | foo @@ -322,7 +321,7 @@ bar group("prints tabs as spaces", () { group("in a single-line span", () { test("before the highlighted section", () { - var span = new SourceFile.fromString("foo\tbar baz").span(4, 7); + var span = SourceFile.fromString("foo\tbar baz").span(4, 7); expect(span.highlight(), equals(""" , @@ -332,7 +331,7 @@ bar }); test("within the highlighted section", () { - var span = new SourceFile.fromString("foo bar\tbaz bang").span(4, 11); + var span = SourceFile.fromString("foo bar\tbaz bang").span(4, 11); expect(span.highlight(), equals(""" , @@ -342,7 +341,7 @@ bar }); test("after the highlighted section", () { - var span = new SourceFile.fromString("foo bar\tbaz").span(4, 7); + var span = SourceFile.fromString("foo bar\tbaz").span(4, 7); expect(span.highlight(), equals(""" , @@ -354,7 +353,7 @@ bar group("in a multi-line span", () { test("before the highlighted section", () { - var span = new SourceFile.fromString(""" + var span = SourceFile.fromString(""" foo\tbar baz whiz bang boom """).span(4, 21); @@ -369,7 +368,7 @@ whiz bang boom }); test("within the first highlighted line", () { - var span = new SourceFile.fromString(""" + var span = SourceFile.fromString(""" foo bar\tbaz whiz bang boom """).span(4, 21); @@ -384,7 +383,7 @@ whiz bang boom }); test("within a middle highlighted line", () { - var span = new SourceFile.fromString(""" + var span = SourceFile.fromString(""" foo bar baz whiz\tbang boom zip zap zop @@ -401,7 +400,7 @@ zip zap zop }); test("within the last highlighted line", () { - var span = new SourceFile.fromString(""" + var span = SourceFile.fromString(""" foo bar baz whiz\tbang boom """).span(4, 21); @@ -416,7 +415,7 @@ whiz\tbang boom }); test("after the highlighted section", () { - var span = new SourceFile.fromString(""" + var span = SourceFile.fromString(""" foo bar baz whiz bang\tboom """).span(4, 21); @@ -434,9 +433,9 @@ whiz bang\tboom group("supports lines of preceding and following context for a span", () { test("within a single line", () { - var span = new SourceSpanWithContext( - new SourceLocation(20, line: 2, column: 5, sourceUrl: "foo.dart"), - new SourceLocation(27, line: 2, column: 12, sourceUrl: "foo.dart"), + var span = SourceSpanWithContext( + SourceLocation(20, line: 2, column: 5, sourceUrl: "foo.dart"), + SourceLocation(27, line: 2, column: 12, sourceUrl: "foo.dart"), "foo bar", "previous\nlines\n-----foo bar-----\nfollowing line\n"); @@ -451,9 +450,9 @@ whiz bang\tboom }); test("covering a full line", () { - var span = new SourceSpanWithContext( - new SourceLocation(15, line: 2, column: 0, sourceUrl: "foo.dart"), - new SourceLocation(33, line: 3, column: 0, sourceUrl: "foo.dart"), + var span = SourceSpanWithContext( + SourceLocation(15, line: 2, column: 0, sourceUrl: "foo.dart"), + SourceLocation(33, line: 3, column: 0, sourceUrl: "foo.dart"), "-----foo bar-----\n", "previous\nlines\n-----foo bar-----\nfollowing line\n"); @@ -468,9 +467,9 @@ whiz bang\tboom }); test("covering multiple full lines", () { - var span = new SourceSpanWithContext( - new SourceLocation(15, line: 2, column: 0, sourceUrl: "foo.dart"), - new SourceLocation(23, line: 4, column: 0, sourceUrl: "foo.dart"), + var span = SourceSpanWithContext( + SourceLocation(15, line: 2, column: 0, sourceUrl: "foo.dart"), + SourceLocation(23, line: 4, column: 0, sourceUrl: "foo.dart"), "foo\nbar\n", "previous\nlines\nfoo\nbar\nfollowing line\n"); diff --git a/pkgs/source_span/test/location_test.dart b/pkgs/source_span/test/location_test.dart index 3a32a92ef..90329362f 100644 --- a/pkgs/source_span/test/location_test.dart +++ b/pkgs/source_span/test/location_test.dart @@ -8,33 +8,30 @@ import 'package:source_span/source_span.dart'; main() { var location; setUp(() { - location = - new SourceLocation(15, line: 2, column: 6, sourceUrl: "foo.dart"); + location = SourceLocation(15, line: 2, column: 6, sourceUrl: "foo.dart"); }); group('errors', () { group('for new SourceLocation()', () { test('offset may not be negative', () { - expect(() => new SourceLocation(-1), throwsRangeError); + expect(() => SourceLocation(-1), throwsRangeError); }); test('line may not be negative', () { - expect(() => new SourceLocation(0, line: -1), throwsRangeError); + expect(() => SourceLocation(0, line: -1), throwsRangeError); }); test('column may not be negative', () { - expect(() => new SourceLocation(0, column: -1), throwsRangeError); + expect(() => SourceLocation(0, column: -1), throwsRangeError); }); }); test('for distance() source URLs must match', () { - expect( - () => location.distance(new SourceLocation(0)), throwsArgumentError); + expect(() => location.distance(SourceLocation(0)), throwsArgumentError); }); test('for compareTo() source URLs must match', () { - expect( - () => location.compareTo(new SourceLocation(0)), throwsArgumentError); + expect(() => location.compareTo(SourceLocation(0)), throwsArgumentError); }); }); @@ -51,13 +48,13 @@ main() { }); test('gracefully handles a missing source URL', () { - var location = new SourceLocation(15, line: 2, column: 6); + var 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 = new SourceLocation(10, sourceUrl: "foo.dart"); + var other = SourceLocation(10, sourceUrl: "foo.dart"); expect(location.distance(other), equals(5)); expect(other.distance(location), equals(5)); }); @@ -71,7 +68,7 @@ main() { group("compareTo()", () { test("sorts by offset", () { - var other = new SourceLocation(20, sourceUrl: "foo.dart"); + var other = SourceLocation(20, sourceUrl: "foo.dart"); expect(location.compareTo(other), lessThan(0)); expect(other.compareTo(location), greaterThan(0)); }); @@ -83,17 +80,17 @@ main() { group("equality", () { test("two locations with the same offset and source are equal", () { - var other = new SourceLocation(15, sourceUrl: "foo.dart"); + var other = SourceLocation(15, sourceUrl: "foo.dart"); expect(location, equals(other)); }); test("a different offset isn't equal", () { - var other = new SourceLocation(10, sourceUrl: "foo.dart"); + var other = SourceLocation(10, sourceUrl: "foo.dart"); expect(location, isNot(equals(other))); }); test("a different source isn't equal", () { - var other = new SourceLocation(15, sourceUrl: "bar.dart"); + var other = SourceLocation(15, sourceUrl: "bar.dart"); expect(location, isNot(equals(other))); }); }); diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart index 99895162a..6a18b4293 100644 --- a/pkgs/source_span/test/span_test.dart +++ b/pkgs/source_span/test/span_test.dart @@ -21,122 +21,114 @@ main() { var span; setUp(() { - span = new SourceSpan(new SourceLocation(5, sourceUrl: "foo.dart"), - new SourceLocation(12, sourceUrl: "foo.dart"), "foo bar"); + span = SourceSpan(SourceLocation(5, sourceUrl: "foo.dart"), + SourceLocation(12, sourceUrl: "foo.dart"), "foo bar"); }); group('errors', () { group('for new SourceSpan()', () { test('source URLs must match', () { - var start = new SourceLocation(0, sourceUrl: "foo.dart"); - var end = new SourceLocation(1, sourceUrl: "bar.dart"); - expect(() => new SourceSpan(start, end, "_"), throwsArgumentError); + var start = SourceLocation(0, sourceUrl: "foo.dart"); + var end = SourceLocation(1, sourceUrl: "bar.dart"); + expect(() => SourceSpan(start, end, "_"), throwsArgumentError); }); test('end must come after start', () { - var start = new SourceLocation(1); - var end = new SourceLocation(0); - expect(() => new SourceSpan(start, end, "_"), throwsArgumentError); + var start = SourceLocation(1); + var end = SourceLocation(0); + expect(() => SourceSpan(start, end, "_"), throwsArgumentError); }); test('text must be the right length', () { - var start = new SourceLocation(0); - var end = new SourceLocation(1); - expect(() => new SourceSpan(start, end, "abc"), throwsArgumentError); + var start = SourceLocation(0); + var end = SourceLocation(1); + expect(() => SourceSpan(start, end, "abc"), throwsArgumentError); }); }); group('for new SourceSpanWithContext()', () { test('context must contain text', () { - var start = new SourceLocation(2); - var end = new SourceLocation(5); - expect(() => new SourceSpanWithContext(start, end, "abc", "--axc--"), + var start = SourceLocation(2); + var end = SourceLocation(5); + expect(() => SourceSpanWithContext(start, end, "abc", "--axc--"), throwsArgumentError); }); test('text starts at start.column in context', () { - var start = new SourceLocation(3); - var end = new SourceLocation(5); - expect(() => new SourceSpanWithContext(start, end, "abc", "--abc--"), + var start = SourceLocation(3); + var end = SourceLocation(5); + expect(() => SourceSpanWithContext(start, end, "abc", "--abc--"), throwsArgumentError); }); test('text starts at start.column of line in multi-line context', () { - var start = new SourceLocation(4, line: 55, column: 3); - var end = new SourceLocation(7, line: 55, column: 6); - expect(() => new SourceSpanWithContext(start, end, "abc", "\n--abc--"), + var start = SourceLocation(4, line: 55, column: 3); + var end = SourceLocation(7, line: 55, column: 6); + expect(() => SourceSpanWithContext(start, end, "abc", "\n--abc--"), throwsArgumentError); - expect( - () => new SourceSpanWithContext(start, end, "abc", "\n----abc--"), + expect(() => SourceSpanWithContext(start, end, "abc", "\n----abc--"), throwsArgumentError); - expect( - () => new SourceSpanWithContext(start, end, "abc", "\n\n--abc--"), + expect(() => SourceSpanWithContext(start, end, "abc", "\n\n--abc--"), throwsArgumentError); // However, these are valid: - new SourceSpanWithContext(start, end, "abc", "\n---abc--"); - new SourceSpanWithContext(start, end, "abc", "\n\n---abc--"); + SourceSpanWithContext(start, end, "abc", "\n---abc--"); + SourceSpanWithContext(start, end, "abc", "\n\n---abc--"); }); test('text can occur multiple times in context', () { - var start1 = new SourceLocation(4, line: 55, column: 2); - var end1 = new SourceLocation(7, line: 55, column: 5); - var start2 = new SourceLocation(4, line: 55, column: 8); - var end2 = new SourceLocation(7, line: 55, column: 11); - new SourceSpanWithContext(start1, end1, "abc", "--abc---abc--\n"); - new SourceSpanWithContext(start1, end1, "abc", "--abc--abc--\n"); - new SourceSpanWithContext(start2, end2, "abc", "--abc---abc--\n"); - new SourceSpanWithContext(start2, end2, "abc", "---abc--abc--\n"); + 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); + SourceSpanWithContext(start1, end1, "abc", "--abc---abc--\n"); + SourceSpanWithContext(start1, end1, "abc", "--abc--abc--\n"); + SourceSpanWithContext(start2, end2, "abc", "--abc---abc--\n"); + SourceSpanWithContext(start2, end2, "abc", "---abc--abc--\n"); expect( - () => new SourceSpanWithContext( - start1, end1, "abc", "---abc--abc--\n"), + () => SourceSpanWithContext(start1, end1, "abc", "---abc--abc--\n"), throwsArgumentError); expect( - () => new SourceSpanWithContext( - start2, end2, "abc", "--abc--abc--\n"), + () => SourceSpanWithContext(start2, end2, "abc", "--abc--abc--\n"), throwsArgumentError); }); }); group('for union()', () { test('source URLs must match', () { - var other = new SourceSpan( - new SourceLocation(12, sourceUrl: "bar.dart"), - new SourceLocation(13, sourceUrl: "bar.dart"), - "_"); + var 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 = new SourceSpan( - new SourceLocation(13, sourceUrl: 'foo.dart'), - new SourceLocation(14, sourceUrl: 'foo.dart'), - "_"); + var other = SourceSpan(SourceLocation(13, sourceUrl: 'foo.dart'), + SourceLocation(14, sourceUrl: 'foo.dart'), "_"); expect(() => span.union(other), throwsArgumentError); }); }); test('for compareTo() source URLs must match', () { - var other = new SourceSpan(new SourceLocation(12, sourceUrl: "bar.dart"), - new SourceLocation(13, sourceUrl: "bar.dart"), "_"); + var other = SourceSpan(SourceLocation(12, sourceUrl: "bar.dart"), + SourceLocation(13, sourceUrl: "bar.dart"), "_"); expect(() => span.compareTo(other), throwsArgumentError); }); }); test('fields work correctly', () { - expect(span.start, equals(new SourceLocation(5, sourceUrl: "foo.dart"))); - expect(span.end, equals(new SourceLocation(12, sourceUrl: "foo.dart"))); + expect(span.start, equals(SourceLocation(5, sourceUrl: "foo.dart"))); + expect(span.end, equals(SourceLocation(12, sourceUrl: "foo.dart"))); expect(span.sourceUrl, equals(Uri.parse("foo.dart"))); expect(span.length, equals(7)); }); group("union()", () { test("works with a preceding adjacent span", () { - var other = new SourceSpan(new SourceLocation(0, sourceUrl: "foo.dart"), - new SourceLocation(5, sourceUrl: "foo.dart"), "hey, "); + var other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"), + SourceLocation(5, sourceUrl: "foo.dart"), "hey, "); var result = span.union(other); expect(result.start, equals(other.start)); @@ -145,8 +137,8 @@ main() { }); test("works with a preceding overlapping span", () { - var other = new SourceSpan(new SourceLocation(0, sourceUrl: "foo.dart"), - new SourceLocation(8, sourceUrl: "foo.dart"), "hey, foo"); + var other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"), + SourceLocation(8, sourceUrl: "foo.dart"), "hey, foo"); var result = span.union(other); expect(result.start, equals(other.start)); @@ -155,8 +147,8 @@ main() { }); test("works with a following adjacent span", () { - var other = new SourceSpan(new SourceLocation(12, sourceUrl: "foo.dart"), - new SourceLocation(16, sourceUrl: "foo.dart"), " baz"); + var other = SourceSpan(SourceLocation(12, sourceUrl: "foo.dart"), + SourceLocation(16, sourceUrl: "foo.dart"), " baz"); var result = span.union(other); expect(result.start, equals(span.start)); @@ -165,8 +157,8 @@ main() { }); test("works with a following overlapping span", () { - var other = new SourceSpan(new SourceLocation(9, sourceUrl: "foo.dart"), - new SourceLocation(16, sourceUrl: "foo.dart"), "bar baz"); + var other = SourceSpan(SourceLocation(9, sourceUrl: "foo.dart"), + SourceLocation(16, sourceUrl: "foo.dart"), "bar baz"); var result = span.union(other); expect(result.start, equals(span.start)); @@ -175,15 +167,15 @@ main() { }); test("works with an internal overlapping span", () { - var other = new SourceSpan(new SourceLocation(7, sourceUrl: "foo.dart"), - new SourceLocation(10, sourceUrl: "foo.dart"), "o b"); + var 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 = new SourceSpan(new SourceLocation(0, sourceUrl: "foo.dart"), - new SourceLocation(16, sourceUrl: "foo.dart"), "hey, foo bar baz"); + var other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"), + SourceLocation(16, sourceUrl: "foo.dart"), "hey, foo bar baz"); expect(span.union(other), equals(other)); }); @@ -200,8 +192,7 @@ line 1, column 6 of foo.dart: oh no }); test("gracefully handles a missing source URL", () { - var span = new SourceSpan( - new SourceLocation(5), new SourceLocation(12), "foo bar"); + var span = SourceSpan(SourceLocation(5), SourceLocation(12), "foo bar"); expect(span.message("oh no"), equalsIgnoringWhitespace(""" line 1, column 6: oh no @@ -212,8 +203,7 @@ line 1, column 6: oh no }); test("gracefully handles empty text", () { - var span = - new SourceSpan(new SourceLocation(5), new SourceLocation(5), ""); + var span = SourceSpan(SourceLocation(5), SourceLocation(5), ""); expect(span.message("oh no"), equals("line 1, column 6: oh no")); }); @@ -246,9 +236,9 @@ ${colors.BLUE} '${colors.NONE}""")); }); test("with context, underlines the right column", () { - var spanWithContext = new SourceSpanWithContext( - new SourceLocation(5, sourceUrl: "foo.dart"), - new SourceLocation(12, sourceUrl: "foo.dart"), + var spanWithContext = SourceSpanWithContext( + SourceLocation(5, sourceUrl: "foo.dart"), + SourceLocation(12, sourceUrl: "foo.dart"), "foo bar", "-----foo bar-----"); @@ -263,16 +253,16 @@ ${colors.BLUE} '${colors.NONE}""")); group("compareTo()", () { test("sorts by start location first", () { - var other = new SourceSpan(new SourceLocation(6, sourceUrl: "foo.dart"), - new SourceLocation(14, sourceUrl: "foo.dart"), "oo bar b"); + var other = SourceSpan(SourceLocation(6, sourceUrl: "foo.dart"), + SourceLocation(14, sourceUrl: "foo.dart"), "oo bar b"); expect(span.compareTo(other), lessThan(0)); expect(other.compareTo(span), greaterThan(0)); }); test("sorts by length second", () { - var other = new SourceSpan(new SourceLocation(5, sourceUrl: "foo.dart"), - new SourceLocation(14, sourceUrl: "foo.dart"), "foo bar b"); + var other = SourceSpan(SourceLocation(5, sourceUrl: "foo.dart"), + SourceLocation(14, sourceUrl: "foo.dart"), "foo bar b"); expect(span.compareTo(other), lessThan(0)); expect(other.compareTo(span), greaterThan(0)); @@ -285,29 +275,29 @@ ${colors.BLUE} '${colors.NONE}""")); group("equality", () { test("two spans with the same locations are equal", () { - var other = new SourceSpan(new SourceLocation(5, sourceUrl: "foo.dart"), - new SourceLocation(12, sourceUrl: "foo.dart"), "foo bar"); + var 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 = new SourceSpan(new SourceLocation(0, sourceUrl: "foo.dart"), - new SourceLocation(12, sourceUrl: "foo.dart"), "hey, foo bar"); + var 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 = new SourceSpan(new SourceLocation(5, sourceUrl: "foo.dart"), - new SourceLocation(16, sourceUrl: "foo.dart"), "foo bar baz"); + var 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 = new SourceSpan(new SourceLocation(5, sourceUrl: "bar.dart"), - new SourceLocation(12, sourceUrl: "bar.dart"), "foo bar"); + var other = SourceSpan(SourceLocation(5, sourceUrl: "bar.dart"), + SourceLocation(12, sourceUrl: "bar.dart"), "foo bar"); expect(span, isNot(equals(other))); }); From d65560c0743ad2df0ec646de5b4f71430b7b50ed Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Thu, 7 Nov 2019 11:00:13 -0800 Subject: [PATCH 059/128] Enable package:pedantic lints (dart-lang/source_span#43) Fix one case of `prefer_is_not_empty`. --- pkgs/source_span/analysis_options.yaml | 1 + pkgs/source_span/lib/src/span_mixin.dart | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 pkgs/source_span/analysis_options.yaml diff --git a/pkgs/source_span/analysis_options.yaml b/pkgs/source_span/analysis_options.yaml new file mode 100644 index 000000000..108d1058a --- /dev/null +++ b/pkgs/source_span/analysis_options.yaml @@ -0,0 +1 @@ +include: package:pedantic/analysis_options.yaml diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index 9bf0937ec..75ecb3d1d 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -51,7 +51,7 @@ abstract class SourceSpanMixin implements SourceSpan { buffer.write(': $message'); var highlight = this.highlight(color: color); - if (!highlight.isEmpty) { + if (highlight.isNotEmpty) { buffer.writeln(); buffer.write(highlight); } From ff838908bd75a6b3c1d8cebdb42b7b96f06e9c42 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Thu, 7 Nov 2019 15:26:43 -0800 Subject: [PATCH 060/128] Be more efficient with String.fromCharCodes (dart-lang/source_span#44) Fixes https://github.com/dart-lang/source_span/issues/37 --- pkgs/source_span/lib/src/file.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 5a193d34d..44760c779 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -214,7 +214,7 @@ class SourceFile { /// /// If [end] isn't passed, it defaults to the end of the file. String getText(int start, [int end]) => - String.fromCharCodes(_decodedChars.sublist(start, end)); + String.fromCharCodes(_decodedChars, start, end); } /// A [SourceLocation] within a [SourceFile]. From ecad5bbec29773c9e2050242fd17464f9dbdf953 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Fri, 8 Nov 2019 15:25:50 -0800 Subject: [PATCH 061/128] Enable and fix a number of lints (dart-lang/source_span#45) - Disable implicit casts and fix errors. - Enable lints that are used in other well maintained dart-lang repos. --- pkgs/source_span/analysis_options.yaml | 91 ++++++++++++++++ pkgs/source_span/lib/src/colors.dart | 8 +- pkgs/source_span/lib/src/file.dart | 101 ++++++++++------- pkgs/source_span/lib/src/highlighter.dart | 66 ++++++------ pkgs/source_span/lib/src/location.dart | 20 ++-- pkgs/source_span/lib/src/location_mixin.dart | 13 ++- pkgs/source_span/lib/src/span.dart | 11 +- pkgs/source_span/lib/src/span_exception.dart | 16 +-- pkgs/source_span/lib/src/span_mixin.dart | 37 ++++--- pkgs/source_span/lib/src/utils.dart | 11 +- pkgs/source_span/test/file_test.dart | 74 ++++++------- pkgs/source_span/test/highlight_test.dart | 91 ++++++++-------- pkgs/source_span/test/location_test.dart | 20 ++-- pkgs/source_span/test/span_test.dart | 108 +++++++++---------- pkgs/source_span/test/utils_test.dart | 24 ++--- 15 files changed, 419 insertions(+), 272 deletions(-) diff --git a/pkgs/source_span/analysis_options.yaml b/pkgs/source_span/analysis_options.yaml index 108d1058a..f28d5a1f1 100644 --- a/pkgs/source_span/analysis_options.yaml +++ b/pkgs/source_span/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/pkgs/source_span/lib/src/colors.dart b/pkgs/source_span/lib/src/colors.dart index 2931eea9e..b48d468ca 100644 --- a/pkgs/source_span/lib/src/colors.dart +++ b/pkgs/source_span/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/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 44760c779..97a2f6534 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -12,8 +12,8 @@ import 'span_mixin.dart'; 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 @@ class SourceFile { /// forwards-compatibility, callers should only pass in characters less than /// or equal to `0xFFFF`. SourceFile.decoded(Iterable 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 @@ class SourceFile { /// /// 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 @@ class SourceFile { "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 @@ class SourceFile { /// /// [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 @@ class SourceFile { 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 @@ class SourceFile { /// /// 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 @@ class FileLocation extends SourceLocationMixin implements SourceLocation { } } + @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 @@ abstract class FileSpan implements SourceSpanWithContext { /// 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 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { /// 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 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { } } + @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 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { return span; } + @override bool operator ==(other) { if (other is! FileSpan) return super == other; if (other is! _FileSpan) { @@ -374,25 +399,27 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { } // 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/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index f68e52a3e..94bc85771 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -44,8 +44,8 @@ class Highlighter { /// 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 @@ class Highlighter { /// 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 @@ class Highlighter { 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 @@ class Highlighter { /// 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 @@ class Highlighter { // 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 @@ class Highlighter { 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 @@ class Highlighter { // 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 @@ class Highlighter { // [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 @@ class Highlighter { 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 @@ class Highlighter { 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 @@ class Highlighter { _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 @@ class Highlighter { 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 @@ class Highlighter { _buffer.write(" "); _colorize(() { - _buffer.write(glyph.verticalLine); - _buffer.write(" "); + _buffer..write(glyph.verticalLine)..write(" "); _writeText(line); }); _buffer.writeln(); @@ -323,8 +322,7 @@ class Highlighter { 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 @@ class Highlighter { } _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 @@ class Highlighter { // 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 @@ class Highlighter { _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 @@ class Highlighter { _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 @@ class Highlighter { /// 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/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart index a27188046..c03c98c51 100644 --- a/pkgs/source_span/lib/src/location.dart +++ b/pkgs/source_span/lib/src/location.dart @@ -32,7 +32,7 @@ class SourceLocation implements Comparable { /// /// 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 @@ class SourceLocation implements Comparable { /// 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 @@ class SourceLocation implements Comparable { } } - /// 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 @@ class SourceLocation implements Comparable { /// 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/pkgs/source_span/lib/src/location_mixin.dart b/pkgs/source_span/lib/src/location_mixin.dart index 7d34311fc..bd773ae76 100644 --- a/pkgs/source_span/lib/src/location_mixin.dart +++ b/pkgs/source_span/lib/src/location_mixin.dart @@ -14,35 +14,42 @@ import 'span.dart'; /// 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/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index b32e1ff6a..87ce846b0 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -6,6 +6,7 @@ import 'package:term_glyph/term_glyph.dart' as glyph; 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 { @@ -35,16 +36,17 @@ abstract class SourceSpan implements Comparable { 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 @@ abstract class SourceSpan implements Comparable { /// 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/pkgs/source_span/lib/src/span_exception.dart b/pkgs/source_span/lib/src/span_exception.dart index 6d3448b6c..2ce0f1a5a 100644 --- a/pkgs/source_span/lib/src/span_exception.dart +++ b/pkgs/source_span/lib/src/span_exception.dart @@ -20,16 +20,17 @@ class SourceSpanException implements Exception { 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 SourceSpanException implements Exception { 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/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index 75ecb3d1d..89606114a 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -16,58 +16,69 @@ import 'utils.dart'; /// [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/pkgs/source_span/lib/src/utils.dart b/pkgs/source_span/lib/src/utils.dart index 228b240e0..33791debd 100644 --- a/pkgs/source_span/lib/src/utils.dart +++ b/pkgs/source_span/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 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 obj1, T obj2) => obj1.compareTo(obj2) > 0 ? obj1 : obj2; /// Returns the number of instances of [codeUnit] in [string]. @@ -31,7 +31,7 @@ int findLineStart(String context, String text, int column) { 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 @@ int findLineStart(String context, String text, int column) { 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/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index 6759ca257..2cfe2d4e7 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/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 @@ zip zap zop""", url: "foo.dart"); 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 @@ zip zap zop""", url: "foo.dart"); }); 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 @@ zip zap zop""", url: "bar.dart").span(10, 11); 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 @@ zip zap zop""", url: "bar.dart").span(10, 11); }); 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()); expect(span.start, equals(location)); expect(span.end, equals(location)); @@ -258,26 +258,26 @@ zip zap zop""", url: "bar.dart").span(10, 11); 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 @@ whiz bang boom 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 @@ zip zap zop }); 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())); expect(result.start, equals(other.start)); expect(result.end, equals(span.end)); @@ -358,50 +358,50 @@ zip zap zop }); 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/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index c2156803c..33719bc4a 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/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 @@ main() { glyph.ascii = oldAscii; }); - var file; + SourceFile file; setUp(() { file = SourceFile.fromString(""" foo bar baz @@ -37,7 +38,7 @@ zip zap zop }); 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 @@ zip zap zop }); 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 @@ zip zap zop }); 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 @@ zip zap zop }); test("highlights the full first line if it's empty", () { - var file = SourceFile.fromString(""" + final file = SourceFile.fromString(""" foo bar @@ -241,7 +242,7 @@ bar }); 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 @@ zip zap zop\r 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 @@ zip zap zop"""); }); test("highlights the full last line if it's empty", () { - var file = SourceFile.fromString(""" + final file = SourceFile.fromString(""" foo bar @@ -297,7 +298,7 @@ bar }); 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 @@ bar // 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 @@ bar 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 @@ bar }); 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 @@ bar }); 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 @@ bar 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 @@ whiz bang boom }); 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 @@ whiz bang boom }); 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 @@ zip zap zop }); 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 @@ whiz\tbang boom }); 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 @@ whiz bang\tboom 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 @@ whiz bang\tboom }); 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 @@ whiz bang\tboom }); 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 @@ whiz bang\tboom 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/pkgs/source_span/test/location_test.dart b/pkgs/source_span/test/location_test.dart index 90329362f..c0e9c0786 100644 --- a/pkgs/source_span/test/location_test.dart +++ b/pkgs/source_span/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 @@ main() { }); 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 @@ main() { 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 @@ main() { 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/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart index 6a18b4293..d53e1e0d4 100644 --- a/pkgs/source_span/test/span_test.dart +++ b/pkgs/source_span/test/span_test.dart @@ -8,7 +8,7 @@ import 'package:term_glyph/term_glyph.dart' as glyph; 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 @@ main() { 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 @@ main() { 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 @@ main() { }); 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 @@ main() { 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 @@ main() { }); 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 @@ main() { 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 @@ line 1, column 6 of foo.dart: oh no }); 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 @@ line 1, column 6: oh no }); 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 @@ line 1, column 6 of foo.dart: oh no 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 @@ ${colors.BLUE} '${colors.NONE}""")); }); 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 @@ ${colors.BLUE} '${colors.NONE}""")); 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/pkgs/source_span/test/utils_test.dart b/pkgs/source_span/test/utils_test.dart index a8146e33b..a4a372eec 100644 --- a/pkgs/source_span/test/utils_test.dart +++ b/pkgs/source_span/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 @@ main() { }); 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); }); }); From 35ff0992f8092ef0336947796e514f2a34a655de Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Thu, 14 Nov 2019 11:02:45 -0800 Subject: [PATCH 062/128] Revert "Be more efficient with String.fromCharCodes (dart-lang/source_span#44)" (dart-lang/source_span#46) This reverts commit ff838908bd75a6b3c1d8cebdb42b7b96f06e9c42. This caused an unknown issue in rare cases with the test package. --- pkgs/source_span/lib/src/file.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 97a2f6534..717a4d432 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -214,7 +214,7 @@ class SourceFile { /// /// If [end] isn't passed, it defaults to the end of the file. String getText(int start, [int end]) => - String.fromCharCodes(_decodedChars, start, end); + String.fromCharCodes(_decodedChars.sublist(start, end)); } /// A [SourceLocation] within a [SourceFile]. From be210223a8cd9a4ba808cbb85456cd83fea0044b Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Thu, 14 Nov 2019 13:23:26 -0800 Subject: [PATCH 063/128] Enforce and fix prefer_single_quotes (dart-lang/source_span#47) We will soon be enforcing this with `package:pedantic`. --- pkgs/source_span/analysis_options.yaml | 2 +- pkgs/source_span/lib/src/file.dart | 50 ++--- pkgs/source_span/lib/src/location.dart | 12 +- pkgs/source_span/lib/src/location_mixin.dart | 6 +- pkgs/source_span/lib/src/span_mixin.dart | 6 +- pkgs/source_span/test/file_test.dart | 210 +++++++++--------- pkgs/source_span/test/highlight_test.dart | 212 +++++++++---------- pkgs/source_span/test/span_test.dart | 176 +++++++-------- 8 files changed, 337 insertions(+), 337 deletions(-) diff --git a/pkgs/source_span/analysis_options.yaml b/pkgs/source_span/analysis_options.yaml index f28d5a1f1..929d6fa97 100644 --- a/pkgs/source_span/analysis_options.yaml +++ b/pkgs/source_span/analysis_options.yaml @@ -67,7 +67,7 @@ linter: - prefer_is_empty - prefer_is_not_empty - prefer_null_aware_operators - #- prefer_single_quotes + - prefer_single_quotes - prefer_typing_uninitialized_variables - recursive_getters - slash_for_doc_comments diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 717a4d432..a03a875a5 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -52,7 +52,7 @@ class SourceFile { /// This constructor is deprecated. /// /// Use [new SourceFile.fromString] instead. - @Deprecated("Will be removed in 2.0.0") + @Deprecated('Will be removed in 2.0.0') SourceFile(String text, {url}) : this.decoded(text.runes, url: url); /// Creates a new source file from [text]. @@ -98,10 +98,10 @@ class SourceFile { /// Gets the 0-based line corresponding to [offset]. int getLine(int offset) { if (offset < 0) { - throw RangeError("Offset may not be negative, was $offset."); + throw RangeError('Offset may not be negative, was $offset.'); } else if (offset > length) { - throw RangeError("Offset $offset must not be greater than the number " - "of characters in the file, $length."); + throw RangeError('Offset $offset must not be greater than the number ' + 'of characters in the file, $length.'); } if (offset < _lineStarts.first) return -1; @@ -163,24 +163,24 @@ class SourceFile { /// is used to more efficiently compute the column. int getColumn(int offset, {int line}) { if (offset < 0) { - throw RangeError("Offset may not be negative, was $offset."); + throw RangeError('Offset may not be negative, was $offset.'); } else if (offset > length) { - throw RangeError("Offset $offset must be not be greater than the " - "number of characters in the file, $length."); + throw RangeError('Offset $offset must be not be greater than the ' + 'number of characters in the file, $length.'); } if (line == null) { line = getLine(offset); } else if (line < 0) { - throw RangeError("Line may not be negative, was $line."); + throw RangeError('Line may not be negative, was $line.'); } else if (line >= lines) { - throw RangeError("Line $line must be less than the number of " - "lines in the file, $lines."); + throw RangeError('Line $line must be less than the number of ' + 'lines in the file, $lines.'); } final lineStart = _lineStarts[line]; if (lineStart > offset) { - throw RangeError("Line $line comes after offset $offset."); + throw RangeError('Line $line comes after offset $offset.'); } return offset - lineStart; @@ -193,12 +193,12 @@ class SourceFile { column ??= 0; if (line < 0) { - throw RangeError("Line may not be negative, was $line."); + throw RangeError('Line may not be negative, was $line.'); } else if (line >= lines) { - throw RangeError("Line $line must be less than the number of " - "lines in the file, $lines."); + throw RangeError('Line $line must be less than the number of ' + 'lines in the file, $lines.'); } else if (column < 0) { - throw RangeError("Column may not be negative, was $column."); + throw RangeError('Column may not be negative, was $column.'); } final result = _lineStarts[line] + column; @@ -241,10 +241,10 @@ class FileLocation extends SourceLocationMixin implements SourceLocation { FileLocation._(this.file, this.offset) { if (offset < 0) { - throw RangeError("Offset may not be negative, was $offset."); + throw RangeError('Offset may not be negative, was $offset.'); } else if (offset > file.length) { - throw RangeError("Offset $offset must not be greater than the number " - "of characters in the file, ${file.length}."); + throw RangeError('Offset $offset must not be greater than the number ' + 'of characters in the file, ${file.length}.'); } } @@ -328,7 +328,7 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { // ...unless this is a point span, in which case we want to include the // next line (or the empty string if this is the end of the file). return endLine == file.lines - 1 - ? "" + ? '' : file.getText( file.getOffset(endLine), file.getOffset(endLine + 1)); } @@ -351,10 +351,10 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { if (_end < _start) { throw ArgumentError('End $_end must come after start $_start.'); } else if (_end > file.length) { - throw RangeError("End $_end must not be greater than the number " - "of characters in the file, ${file.length}."); + throw RangeError('End $_end must not be greater than the number ' + 'of characters in the file, ${file.length}.'); } else if (_start < 0) { - throw RangeError("Start may not be negative, was $_start."); + throw RangeError('Start may not be negative, was $_start.'); } } @@ -375,11 +375,11 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { if (other is _FileSpan) { if (_start > other._end || other._start > _end) { - throw ArgumentError("Spans $this and $other are disjoint."); + throw ArgumentError('Spans $this and $other are disjoint.'); } } else { if (_start > other.end.offset || other.start.offset > _end) { - throw ArgumentError("Spans $this and $other are disjoint."); + throw ArgumentError('Spans $this and $other are disjoint.'); } } @@ -409,7 +409,7 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { @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."); } diff --git a/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart index c03c98c51..4f69df5b8 100644 --- a/pkgs/source_span/lib/src/location.dart +++ b/pkgs/source_span/lib/src/location.dart @@ -48,11 +48,11 @@ class SourceLocation implements Comparable { line = line == null ? 0 : line, column = column == null ? offset : column { if (offset < 0) { - throw RangeError("Offset may not be negative, was $offset."); + throw RangeError('Offset may not be negative, was $offset.'); } else if (line != null && line < 0) { - throw RangeError("Line may not be negative, was $line."); + throw RangeError('Line may not be negative, was $line.'); } else if (column != null && column < 0) { - throw RangeError("Column may not be negative, was $column."); + throw RangeError('Column may not be negative, was $column.'); } } @@ -61,14 +61,14 @@ class SourceLocation implements Comparable { /// 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(); } /// Returns a span that covers only a single point: this location. - SourceSpan pointSpan() => SourceSpan(this, this, ""); + SourceSpan pointSpan() => SourceSpan(this, this, ''); /// Compares two locations. /// @@ -76,7 +76,7 @@ class SourceLocation implements Comparable { @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; diff --git a/pkgs/source_span/lib/src/location_mixin.dart b/pkgs/source_span/lib/src/location_mixin.dart index bd773ae76..bbb73b49a 100644 --- a/pkgs/source_span/lib/src/location_mixin.dart +++ b/pkgs/source_span/lib/src/location_mixin.dart @@ -23,19 +23,19 @@ abstract class SourceLocationMixin implements SourceLocation { @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, ""); + 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; diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index 89606114a..55eae94a9 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -31,7 +31,7 @@ abstract class SourceSpanMixin implements SourceSpan { @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."); } @@ -41,7 +41,7 @@ abstract class SourceSpanMixin implements SourceSpan { final endSpan = end == this.end ? this : other; if (beginSpan.end.compareTo(endSpan.start) < 0) { - throw ArgumentError("Spans $this and $other are disjoint."); + throw ArgumentError('Spans $this and $other are disjoint.'); } final text = beginSpan.text + @@ -68,7 +68,7 @@ abstract class SourceSpanMixin implements SourceSpan { @override String highlight({color}) { - if (this is! SourceSpanWithContext && length == 0) return ""; + if (this is! SourceSpanWithContext && length == 0) return ''; return Highlighter(this, color: color).highlight(); } diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index 2cfe2d4e7..499f8ef41 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/test/file_test.dart @@ -8,236 +8,236 @@ import 'package:source_span/source_span.dart'; void main() { SourceFile file; setUp(() { - file = SourceFile.fromString(""" + file = SourceFile.fromString(''' foo bar baz whiz bang boom -zip zap zop""", url: "foo.dart"); +zip zap zop''', url: 'foo.dart'); }); - group("errors", () { - group("for span()", () { - test("end must come after start", () { + group('errors', () { + group('for span()', () { + test('end must come after start', () { expect(() => file.span(10, 5), throwsArgumentError); }); - test("start may not be negative", () { + test('start may not be negative', () { expect(() => file.span(-1, 5), throwsRangeError); }); - test("end may not be outside the file", () { + test('end may not be outside the file', () { expect(() => file.span(10, 100), throwsRangeError); }); }); - group("for location()", () { - test("offset may not be negative", () { + group('for location()', () { + test('offset may not be negative', () { expect(() => file.location(-1), throwsRangeError); }); - test("offset may not be outside the file", () { + test('offset may not be outside the file', () { expect(() => file.location(100), throwsRangeError); }); }); - group("for getLine()", () { - test("offset may not be negative", () { + group('for getLine()', () { + test('offset may not be negative', () { expect(() => file.getLine(-1), throwsRangeError); }); - test("offset may not be outside the file", () { + test('offset may not be outside the file', () { expect(() => file.getLine(100), throwsRangeError); }); }); - group("for getColumn()", () { - test("offset may not be negative", () { + group('for getColumn()', () { + test('offset may not be negative', () { expect(() => file.getColumn(-1), throwsRangeError); }); - test("offset may not be outside the file", () { + test('offset may not be outside the file', () { expect(() => file.getColumn(100), throwsRangeError); }); - test("line may not be negative", () { + test('line may not be negative', () { expect(() => file.getColumn(1, line: -1), throwsRangeError); }); - test("line may not be outside the file", () { + test('line may not be outside the file', () { expect(() => file.getColumn(1, line: 100), throwsRangeError); }); - test("line must be accurate", () { + test('line must be accurate', () { expect(() => file.getColumn(1, line: 1), throwsRangeError); }); }); - group("getOffset()", () { - test("line may not be negative", () { + group('getOffset()', () { + test('line may not be negative', () { expect(() => file.getOffset(-1), throwsRangeError); }); - test("column may not be negative", () { + test('column may not be negative', () { expect(() => file.getOffset(1, -1), throwsRangeError); }); - test("line may not be outside the file", () { + test('line may not be outside the file', () { expect(() => file.getOffset(100), throwsRangeError); }); - test("column may not be outside the file", () { + test('column may not be outside the file', () { expect(() => file.getOffset(2, 100), throwsRangeError); }); - test("column may not be outside the line", () { + test('column may not be outside the line', () { expect(() => file.getOffset(1, 20), throwsRangeError); }); }); - group("for getText()", () { - test("end must come after start", () { + group('for getText()', () { + test('end must come after start', () { expect(() => file.getText(10, 5), throwsArgumentError); }); - test("start may not be negative", () { + test('start may not be negative', () { expect(() => file.getText(-1, 5), throwsRangeError); }); - test("end may not be outside the file", () { + test('end may not be outside the file', () { expect(() => file.getText(10, 100), throwsRangeError); }); }); - group("for span().union()", () { - test("source URLs must match", () { - final other = SourceSpan(SourceLocation(10), SourceLocation(11), "_"); + group('for span().union()', () { + test('source URLs must match', () { + final other = SourceSpan(SourceLocation(10), SourceLocation(11), '_'); expect(() => file.span(9, 10).union(other), throwsArgumentError); }); - test("spans may not be disjoint", () { + test('spans may not be disjoint', () { expect(() => file.span(9, 10).union(file.span(11, 12)), throwsArgumentError); }); }); - test("for span().expand() source URLs must match", () { - final other = SourceFile.fromString(""" + test('for span().expand() source URLs must match', () { + final other = SourceFile.fromString(''' foo bar baz whiz bang boom -zip zap zop""", url: "bar.dart").span(10, 11); +zip zap zop''', url: 'bar.dart').span(10, 11); expect(() => file.span(9, 10).expand(other), throwsArgumentError); }); }); test('fields work correctly', () { - expect(file.url, equals(Uri.parse("foo.dart"))); + expect(file.url, equals(Uri.parse('foo.dart'))); expect(file.lines, equals(3)); expect(file.length, equals(38)); }); - group("new SourceFile()", () { - test("handles CRLF correctly", () { - expect(SourceFile.fromString("foo\r\nbar").getLine(6), equals(1)); + group('new SourceFile()', () { + test('handles CRLF correctly', () { + expect(SourceFile.fromString('foo\r\nbar').getLine(6), equals(1)); }); - test("handles a lone CR correctly", () { - expect(SourceFile.fromString("foo\rbar").getLine(5), equals(1)); + test('handles a lone CR correctly', () { + expect(SourceFile.fromString('foo\rbar').getLine(5), equals(1)); }); }); - group("span()", () { - test("returns a span between the given offsets", () { + group('span()', () { + test('returns a span between the given offsets', () { 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", () { + test('end defaults to the end of the file', () { final span = file.span(5); expect(span.start, equals(file.location(5))); expect(span.end, equals(file.location(file.length))); }); }); - group("getLine()", () { - test("works for a middle character on the line", () { + group('getLine()', () { + test('works for a middle character on the line', () { expect(file.getLine(15), equals(1)); }); - test("works for the first character of a line", () { + test('works for the first character of a line', () { expect(file.getLine(12), equals(1)); }); - test("works for a newline character", () { + test('works for a newline character', () { expect(file.getLine(11), equals(0)); }); - test("works for the last offset", () { + test('works for the last offset', () { expect(file.getLine(file.length), equals(2)); }); }); - group("getColumn()", () { - test("works for a middle character on the line", () { + group('getColumn()', () { + test('works for a middle character on the line', () { expect(file.getColumn(15), equals(3)); }); - test("works for the first character of a line", () { + test('works for the first character of a line', () { expect(file.getColumn(12), equals(0)); }); - test("works for a newline character", () { + test('works for a newline character', () { expect(file.getColumn(11), equals(11)); }); - test("works when line is passed as well", () { + test('works when line is passed as well', () { expect(file.getColumn(12, line: 1), equals(0)); }); - test("works for the last offset", () { + test('works for the last offset', () { expect(file.getColumn(file.length), equals(11)); }); }); - group("getOffset()", () { - test("works for a middle character on the line", () { + group('getOffset()', () { + test('works for a middle character on the line', () { expect(file.getOffset(1, 3), equals(15)); }); - test("works for the first character of a line", () { + test('works for the first character of a line', () { expect(file.getOffset(1), equals(12)); }); - test("works for a newline character", () { + test('works for a newline character', () { expect(file.getOffset(0, 11), equals(11)); }); - test("works for the last offset", () { + test('works for the last offset', () { expect(file.getOffset(2, 11), equals(file.length)); }); }); - group("getText()", () { - test("returns a substring of the source", () { - expect(file.getText(8, 15), equals("baz\nwhi")); + group('getText()', () { + test('returns a substring of the source', () { + expect(file.getText(8, 15), equals('baz\nwhi')); }); - test("end defaults to the end of the file", () { - expect(file.getText(20), equals("g boom\nzip zap zop")); + test('end defaults to the end of the file', () { + expect(file.getText(20), equals('g boom\nzip zap zop')); }); }); - group("FileLocation", () { - test("reports the correct line number", () { + group('FileLocation', () { + test('reports the correct line number', () { expect(file.location(15).line, equals(1)); }); - test("reports the correct column number", () { + test('reports the correct column number', () { expect(file.location(15).column, equals(3)); }); - test("pointSpan() returns a FileSpan", () { + test('pointSpan() returns a FileSpan', () { final location = file.location(15); final span = location.pointSpan(); expect(span, isA()); @@ -247,46 +247,46 @@ zip zap zop""", url: "bar.dart").span(10, 11); }); }); - group("FileSpan", () { - test("text returns a substring of the source", () { - expect(file.span(8, 15).text, equals("baz\nwhi")); + group('FileSpan', () { + test('text returns a substring of the source', () { + expect(file.span(8, 15).text, equals('baz\nwhi')); }); - test("text includes the last char when end is defaulted to EOF", () { - expect(file.span(29).text, equals("p zap zop")); + test('text includes the last char when end is defaulted to EOF', () { + expect(file.span(29).text, equals('p zap zop')); }); - group("context", () { + group('context', () { test("contains the span's text", () { 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", + test('contains the previous line for a point span at the end of a line', () { 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", + test('contains the next line for a point span at the beginning of a line', () { 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", () { + group('for a point span at the end of a file', () { + test('without a newline, contains the last line', () { final span = file.span(file.length, file.length); expect(span.context, equals('zip zap zop')); }); - test("with a newline, contains an empty line", () { - file = SourceFile.fromString(""" + test('with a newline, contains an empty line', () { + file = SourceFile.fromString(''' foo bar baz whiz bang boom zip zap zop -""", url: "foo.dart"); +''', url: 'foo.dart'); final span = file.span(file.length, file.length); expect(span.context, isEmpty); @@ -294,92 +294,92 @@ zip zap zop }); }); - group("union()", () { + group('union()', () { FileSpan span; setUp(() { span = file.span(5, 12); }); - test("works with a preceding adjacent span", () { + test('works with a preceding adjacent span', () { 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")); + expect(result.text, equals('foo bar baz\n')); }); - test("works with a preceding overlapping span", () { + test('works with a preceding overlapping span', () { 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")); + expect(result.text, equals('foo bar baz\n')); }); - test("works with a following adjacent span", () { + test('works with a following adjacent span', () { 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")); + expect(result.text, equals('ar baz\nwhiz')); }); - test("works with a following overlapping span", () { + test('works with a following overlapping span', () { 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")); + expect(result.text, equals('ar baz\nwhiz')); }); - test("works with an internal overlapping span", () { + test('works with an internal overlapping span', () { final other = file.span(7, 10); expect(span.union(other), equals(span)); }); - test("works with an external overlapping span", () { + test('works with an external overlapping span', () { final other = file.span(0, 16); expect(span.union(other), equals(other)); }); - test("returns a FileSpan for a FileSpan input", () { + test('returns a FileSpan for a FileSpan input', () { expect(span.union(file.span(0, 5)), isA()); }); - test("returns a base SourceSpan for a SourceSpan input", () { - final other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"), - SourceLocation(5, sourceUrl: "foo.dart"), "hey, "); + test('returns a base SourceSpan for a SourceSpan input', () { + final other = SourceSpan(SourceLocation(0, sourceUrl: 'foo.dart'), + SourceLocation(5, sourceUrl: 'foo.dart'), 'hey, '); final result = span.union(other); expect(result, isNot(isA())); expect(result.start, equals(other.start)); expect(result.end, equals(span.end)); - expect(result.text, equals("hey, ar baz\n")); + expect(result.text, equals('hey, ar baz\n')); }); }); - group("expand()", () { + group('expand()', () { FileSpan span; setUp(() { span = file.span(5, 12); }); - test("works with a preceding nonadjacent span", () { + test('works with a preceding nonadjacent span', () { 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")); + expect(result.text, equals('foo bar baz\n')); }); - test("works with a preceding overlapping span", () { + test('works with a preceding overlapping span', () { 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")); + expect(result.text, equals('foo bar baz\n')); }); - test("works with a following nonadjacent span", () { + test('works with a following nonadjacent span', () { final other = file.span(14, 16); final result = span.expand(other); expect(result.start, equals(span.start)); diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index 33719bc4a..9d95b21ef 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -22,14 +22,14 @@ void main() { SourceFile file; setUp(() { - file = SourceFile.fromString(""" + file = SourceFile.fromString(''' foo bar baz whiz bang boom zip zap zop -"""); +'''); }); - test("points to the span in the source", () { + test('points to the span in the source', () { expect(file.span(4, 7).highlight(), equals(""" , 1 | foo bar baz @@ -37,8 +37,8 @@ zip zap zop '""")); }); - test("gracefully handles a missing source URL", () { - final span = SourceFile.fromString("foo bar baz").span(4, 7); + test('gracefully handles a missing source URL', () { + final span = SourceFile.fromString('foo bar baz').span(4, 7); expect(span.highlight(), equals(""" , 1 | foo bar baz @@ -46,8 +46,8 @@ zip zap zop '""")); }); - group("highlights a point span", () { - test("in the middle of a line", () { + group('highlights a point span', () { + test('in the middle of a line', () { expect(file.location(4).pointSpan().highlight(), equals(""" , 1 | foo bar baz @@ -55,7 +55,7 @@ zip zap zop '""")); }); - test("at the beginning of the file", () { + test('at the beginning of the file', () { expect(file.location(0).pointSpan().highlight(), equals(""" , 1 | foo bar baz @@ -63,7 +63,7 @@ zip zap zop '""")); }); - test("at the beginning of a line", () { + test('at the beginning of a line', () { expect(file.location(12).pointSpan().highlight(), equals(""" , 2 | whiz bang boom @@ -71,7 +71,7 @@ zip zap zop '""")); }); - test("at the end of a line", () { + test('at the end of a line', () { expect(file.location(11).pointSpan().highlight(), equals(""" , 1 | foo bar baz @@ -79,7 +79,7 @@ zip zap zop '""")); }); - test("at the end of the file", () { + test('at the end of the file', () { expect(file.location(38).pointSpan().highlight(), equals(""" , 3 | zip zap zop @@ -87,7 +87,7 @@ zip zap zop '""")); }); - test("after the end of the file", () { + test('after the end of the file', () { expect(file.location(39).pointSpan().highlight(), equals(""" , 4 | @@ -95,8 +95,8 @@ zip zap zop '""")); }); - test("at the end of the file with no trailing newline", () { - file = SourceFile.fromString("zip zap zop"); + test('at the end of the file with no trailing newline', () { + file = SourceFile.fromString('zip zap zop'); expect(file.location(10).pointSpan().highlight(), equals(""" , 1 | zip zap zop @@ -104,8 +104,8 @@ zip zap zop '""")); }); - test("after the end of the file with no trailing newline", () { - file = SourceFile.fromString("zip zap zop"); + test('after the end of the file with no trailing newline', () { + file = SourceFile.fromString('zip zap zop'); expect(file.location(11).pointSpan().highlight(), equals(""" , 1 | zip zap zop @@ -113,8 +113,8 @@ zip zap zop '""")); }); - test("in an empty file", () { - expect(SourceFile.fromString("").location(0).pointSpan().highlight(), + test('in an empty file', () { + expect(SourceFile.fromString('').location(0).pointSpan().highlight(), equals(""" , 1 | @@ -122,8 +122,8 @@ zip zap zop '""")); }); - test("on an empty line", () { - final file = SourceFile.fromString("foo\n\nbar"); + test('on an empty line', () { + final file = SourceFile.fromString('foo\n\nbar'); expect(file.location(4).pointSpan().highlight(), equals(""" , 2 | @@ -132,25 +132,25 @@ zip zap zop }); }); - test("highlights a single-line file without a newline", () { - expect(SourceFile.fromString("foo bar").span(0, 7).highlight(), equals(""" + test('highlights a single-line file without a newline', () { + expect(SourceFile.fromString('foo bar').span(0, 7).highlight(), equals(""" , 1 | foo bar | ^^^^^^^ '""")); }); - test("highlights a single empty line", () { + test('highlights a single empty line', () { expect( - SourceFile.fromString("foo\n\nbar").span(4, 5).highlight(), equals(""" + SourceFile.fromString('foo\n\nbar').span(4, 5).highlight(), equals(""" , 2 | | ^ '""")); }); - group("with a multiline span", () { - test("highlights the middle of the first and last lines", () { + group('with a multiline span', () { + test('highlights the middle of the first and last lines', () { expect(file.span(4, 34).highlight(), equals(""" , 1 | foo bar baz @@ -161,7 +161,7 @@ zip zap zop '""")); }); - test("works when it begins at the end of a line", () { + test('works when it begins at the end of a line', () { expect(file.span(11, 34).highlight(), equals(""" , 1 | foo bar baz @@ -172,7 +172,7 @@ zip zap zop '""")); }); - test("works when it ends at the beginning of a line", () { + test('works when it ends at the beginning of a line', () { expect(file.span(4, 28).highlight(), equals(""" , 1 | foo bar baz @@ -183,7 +183,7 @@ zip zap zop '""")); }); - test("highlights the full first line", () { + test('highlights the full first line', () { expect(file.span(0, 34).highlight(), equals(""" , 1 | / foo bar baz @@ -194,11 +194,11 @@ zip zap zop }); test("highlights the full first line even if it's indented", () { - final file = SourceFile.fromString(""" + final file = SourceFile.fromString(''' foo bar baz whiz bang boom zip zap zop -"""); +'''); expect(file.span(2, 38).highlight(), equals(""" , @@ -210,11 +210,11 @@ zip zap zop }); test("highlights the full first line if it's empty", () { - final file = SourceFile.fromString(""" + final file = SourceFile.fromString(''' foo bar -"""); +'''); expect(file.span(4, 9).highlight(), equals(""" , @@ -223,7 +223,7 @@ bar '""")); }); - test("highlights the full last line", () { + test('highlights the full last line', () { expect(file.span(4, 27).highlight(), equals(""" , 1 | foo bar baz @@ -232,7 +232,7 @@ bar '""")); }); - test("highlights the full last line with no trailing newline", () { + test('highlights the full last line with no trailing newline', () { expect(file.span(4, 26).highlight(), equals(""" , 1 | foo bar baz @@ -241,12 +241,12 @@ bar '""")); }); - test("highlights the full last line with a trailing Windows newline", () { - final file = SourceFile.fromString(""" + test('highlights the full last line with a trailing Windows newline', () { + final file = SourceFile.fromString(''' foo bar baz\r whiz bang boom\r zip zap zop\r -"""); +'''); expect(file.span(4, 29).highlight(), equals(""" , @@ -256,7 +256,7 @@ zip zap zop\r '""")); }); - test("highlights the full last line at the end of the file", () { + test('highlights the full last line at the end of the file', () { expect(file.span(4, 39).highlight(), equals(""" , 1 | foo bar baz @@ -267,12 +267,12 @@ zip zap zop\r }); test( - "highlights the full last line at the end of the file with no trailing " - "newline", () { - final file = SourceFile.fromString(""" + 'highlights the full last line at the end of the file with no trailing ' + 'newline', () { + final file = SourceFile.fromString(''' foo bar baz whiz bang boom -zip zap zop"""); +zip zap zop'''); expect(file.span(4, 38).highlight(), equals(""" , @@ -284,11 +284,11 @@ zip zap zop"""); }); test("highlights the full last line if it's empty", () { - final file = SourceFile.fromString(""" + final file = SourceFile.fromString(''' foo bar -"""); +'''); expect(file.span(0, 5).highlight(), equals(""" , @@ -297,8 +297,8 @@ bar '""")); }); - test("highlights multiple empty lines", () { - final file = SourceFile.fromString("foo\n\n\n\nbar"); + test('highlights multiple empty lines', () { + final file = SourceFile.fromString('foo\n\n\n\nbar'); expect(file.span(4, 7).highlight(), equals(""" , 2 | / @@ -308,8 +308,8 @@ bar }); // Regression test for #32 - test("highlights the end of a line and an empty line", () { - final file = SourceFile.fromString("foo\n\n"); + test('highlights the end of a line and an empty line', () { + final file = SourceFile.fromString('foo\n\n'); expect(file.span(3, 5).highlight(), equals(""" , 1 | foo @@ -319,10 +319,10 @@ bar }); }); - group("prints tabs as spaces", () { - group("in a single-line span", () { - test("before the highlighted section", () { - final span = SourceFile.fromString("foo\tbar baz").span(4, 7); + group('prints tabs as spaces', () { + group('in a single-line span', () { + test('before the highlighted section', () { + final span = SourceFile.fromString('foo\tbar baz').span(4, 7); expect(span.highlight(), equals(""" , @@ -331,8 +331,8 @@ bar '""")); }); - test("within the highlighted section", () { - final span = SourceFile.fromString("foo bar\tbaz bang").span(4, 11); + test('within the highlighted section', () { + final span = SourceFile.fromString('foo bar\tbaz bang').span(4, 11); expect(span.highlight(), equals(""" , @@ -341,8 +341,8 @@ bar '""")); }); - test("after the highlighted section", () { - final span = SourceFile.fromString("foo bar\tbaz").span(4, 7); + test('after the highlighted section', () { + final span = SourceFile.fromString('foo bar\tbaz').span(4, 7); expect(span.highlight(), equals(""" , @@ -352,12 +352,12 @@ bar }); }); - group("in a multi-line span", () { - test("before the highlighted section", () { - final span = SourceFile.fromString(""" + group('in a multi-line span', () { + test('before the highlighted section', () { + final span = SourceFile.fromString(''' foo\tbar baz whiz bang boom -""").span(4, 21); +''').span(4, 21); expect(span.highlight(), equals(""" , @@ -368,11 +368,11 @@ whiz bang boom '""")); }); - test("within the first highlighted line", () { - final span = SourceFile.fromString(""" + test('within the first highlighted line', () { + final span = SourceFile.fromString(''' foo bar\tbaz whiz bang boom -""").span(4, 21); +''').span(4, 21); expect(span.highlight(), equals(""" , @@ -383,12 +383,12 @@ whiz bang boom '""")); }); - test("within a middle highlighted line", () { - final span = SourceFile.fromString(""" + test('within a middle highlighted line', () { + final span = SourceFile.fromString(''' foo bar baz whiz\tbang boom zip zap zop -""").span(4, 34); +''').span(4, 34); expect(span.highlight(), equals(""" , @@ -400,11 +400,11 @@ zip zap zop '""")); }); - test("within the last highlighted line", () { - final span = SourceFile.fromString(""" + test('within the last highlighted line', () { + final span = SourceFile.fromString(''' foo bar baz whiz\tbang boom -""").span(4, 21); +''').span(4, 21); expect(span.highlight(), equals(""" , @@ -415,11 +415,11 @@ whiz\tbang boom '""")); }); - test("after the highlighted section", () { - final span = SourceFile.fromString(""" + test('after the highlighted section', () { + final span = SourceFile.fromString(''' foo bar baz whiz bang\tboom -""").span(4, 21); +''').span(4, 21); expect(span.highlight(), equals(""" , @@ -432,13 +432,13 @@ whiz bang\tboom }); }); - group("supports lines of preceding and following context for a span", () { - test("within a single line", () { + group('supports lines of preceding and following context for a span', () { + test('within a single line', () { final span = SourceSpanWithContext( - SourceLocation(20, line: 2, column: 5, sourceUrl: "foo.dart"), - SourceLocation(27, line: 2, column: 12, sourceUrl: "foo.dart"), - "foo bar", - "previous\nlines\n-----foo bar-----\nfollowing line\n"); + SourceLocation(20, line: 2, column: 5, sourceUrl: 'foo.dart'), + SourceLocation(27, line: 2, column: 12, sourceUrl: 'foo.dart'), + 'foo bar', + 'previous\nlines\n-----foo bar-----\nfollowing line\n'); expect(span.highlight(), equals(""" , @@ -450,12 +450,12 @@ whiz bang\tboom '""")); }); - test("covering a full line", () { + test('covering a full line', () { final span = SourceSpanWithContext( - SourceLocation(15, line: 2, column: 0, sourceUrl: "foo.dart"), - SourceLocation(33, line: 3, column: 0, sourceUrl: "foo.dart"), - "-----foo bar-----\n", - "previous\nlines\n-----foo bar-----\nfollowing line\n"); + SourceLocation(15, line: 2, column: 0, sourceUrl: 'foo.dart'), + SourceLocation(33, line: 3, column: 0, sourceUrl: 'foo.dart'), + '-----foo bar-----\n', + 'previous\nlines\n-----foo bar-----\nfollowing line\n'); expect(span.highlight(), equals(""" , @@ -467,12 +467,12 @@ whiz bang\tboom '""")); }); - test("covering multiple full lines", () { + test('covering multiple full lines', () { final span = SourceSpanWithContext( - SourceLocation(15, line: 2, column: 0, sourceUrl: "foo.dart"), - SourceLocation(23, line: 4, column: 0, sourceUrl: "foo.dart"), - "foo\nbar\n", - "previous\nlines\nfoo\nbar\nfollowing line\n"); + SourceLocation(15, line: 2, column: 0, sourceUrl: 'foo.dart'), + SourceLocation(23, line: 4, column: 0, sourceUrl: 'foo.dart'), + 'foo\nbar\n', + 'previous\nlines\nfoo\nbar\nfollowing line\n'); expect(span.highlight(), equals(""" , @@ -485,7 +485,7 @@ whiz bang\tboom }); }); - group("colors", () { + group('colors', () { test("doesn't colorize if color is false", () { expect(file.span(4, 7).highlight(color: false), equals(""" , @@ -494,47 +494,47 @@ whiz bang\tboom '""")); }); - test("colorizes if color is true", () { - expect(file.span(4, 7).highlight(color: true), equals(""" + 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}''')); }); test("uses the given color if it's passed", () { - expect(file.span(4, 7).highlight(color: colors.yellow), equals(""" + 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}""")); +${colors.blue} '${colors.none}''')); }); - test("colorizes a multiline span", () { - expect(file.span(4, 34).highlight(color: true), equals(""" + 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}''')); }); - test("colorizes a multiline span that highlights full lines", () { - expect(file.span(0, 39).highlight(color: true), equals(""" + 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}''')); }); }); - group("line numbers have appropriate padding", () { - test("with line number 9", () { + group('line numbers have appropriate padding', () { + test('with line number 9', () { expect( - SourceFile.fromString("\n" * 8 + "foo bar baz\n") + SourceFile.fromString('\n' * 8 + 'foo bar baz\n') .span(8, 11) .highlight(), equals(""" @@ -544,9 +544,9 @@ ${colors.blue} '${colors.none}""")); '""")); }); - test("with line number 10", () { + test('with line number 10', () { expect( - SourceFile.fromString("\n" * 9 + "foo bar baz\n") + SourceFile.fromString('\n' * 9 + 'foo bar baz\n') .span(9, 12) .highlight(), equals(""" diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart index d53e1e0d4..1ac9d35ef 100644 --- a/pkgs/source_span/test/span_test.dart +++ b/pkgs/source_span/test/span_test.dart @@ -21,28 +21,28 @@ void main() { SourceSpan span; setUp(() { - span = SourceSpan(SourceLocation(5, sourceUrl: "foo.dart"), - SourceLocation(12, sourceUrl: "foo.dart"), "foo bar"); + span = SourceSpan(SourceLocation(5, sourceUrl: 'foo.dart'), + SourceLocation(12, sourceUrl: 'foo.dart'), 'foo bar'); }); group('errors', () { group('for new SourceSpan()', () { test('source URLs must match', () { - final start = SourceLocation(0, sourceUrl: "foo.dart"); - final end = SourceLocation(1, sourceUrl: "bar.dart"); - expect(() => SourceSpan(start, end, "_"), throwsArgumentError); + 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', () { final start = SourceLocation(1); final end = SourceLocation(0); - expect(() => SourceSpan(start, end, "_"), throwsArgumentError); + expect(() => SourceSpan(start, end, '_'), throwsArgumentError); }); test('text must be the right length', () { final start = SourceLocation(0); final end = SourceLocation(1); - expect(() => SourceSpan(start, end, "abc"), throwsArgumentError); + expect(() => SourceSpan(start, end, 'abc'), throwsArgumentError); }); }); @@ -50,30 +50,30 @@ void main() { test('context must contain text', () { final start = SourceLocation(2); final end = SourceLocation(5); - expect(() => SourceSpanWithContext(start, end, "abc", "--axc--"), + expect(() => SourceSpanWithContext(start, end, 'abc', '--axc--'), throwsArgumentError); }); test('text starts at start.column in context', () { final start = SourceLocation(3); final end = SourceLocation(5); - expect(() => SourceSpanWithContext(start, end, "abc", "--abc--"), + expect(() => SourceSpanWithContext(start, end, 'abc', '--abc--'), throwsArgumentError); }); test('text starts at start.column of line in multi-line context', () { final start = SourceLocation(4, line: 55, column: 3); final end = SourceLocation(7, line: 55, column: 6); - expect(() => SourceSpanWithContext(start, end, "abc", "\n--abc--"), + expect(() => SourceSpanWithContext(start, end, 'abc', '\n--abc--'), throwsArgumentError); - expect(() => SourceSpanWithContext(start, end, "abc", "\n----abc--"), + expect(() => SourceSpanWithContext(start, end, 'abc', '\n----abc--'), throwsArgumentError); - expect(() => SourceSpanWithContext(start, end, "abc", "\n\n--abc--"), + expect(() => SourceSpanWithContext(start, end, 'abc', '\n\n--abc--'), throwsArgumentError); // However, these are valid: - SourceSpanWithContext(start, end, "abc", "\n---abc--"); - SourceSpanWithContext(start, end, "abc", "\n\n---abc--"); + SourceSpanWithContext(start, end, 'abc', '\n---abc--'); + SourceSpanWithContext(start, end, 'abc', '\n\n---abc--'); }); test('text can occur multiple times in context', () { @@ -81,109 +81,109 @@ void main() { 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"); - SourceSpanWithContext(start2, end2, "abc", "---abc--abc--\n"); + SourceSpanWithContext(start1, end1, 'abc', '--abc---abc--\n'); + SourceSpanWithContext(start1, end1, 'abc', '--abc--abc--\n'); + SourceSpanWithContext(start2, end2, 'abc', '--abc---abc--\n'); + SourceSpanWithContext(start2, end2, 'abc', '---abc--abc--\n'); expect( - () => SourceSpanWithContext(start1, end1, "abc", "---abc--abc--\n"), + () => SourceSpanWithContext(start1, end1, 'abc', '---abc--abc--\n'), throwsArgumentError); expect( - () => SourceSpanWithContext(start2, end2, "abc", "--abc--abc--\n"), + () => SourceSpanWithContext(start2, end2, 'abc', '--abc--abc--\n'), throwsArgumentError); }); }); group('for union()', () { test('source URLs must match', () { - final other = SourceSpan(SourceLocation(12, sourceUrl: "bar.dart"), - SourceLocation(13, 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', () { final other = SourceSpan(SourceLocation(13, sourceUrl: 'foo.dart'), - SourceLocation(14, sourceUrl: 'foo.dart'), "_"); + SourceLocation(14, sourceUrl: 'foo.dart'), '_'); expect(() => span.union(other), throwsArgumentError); }); }); test('for compareTo() source URLs must match', () { - final other = SourceSpan(SourceLocation(12, sourceUrl: "bar.dart"), - SourceLocation(13, sourceUrl: "bar.dart"), "_"); + final other = SourceSpan(SourceLocation(12, sourceUrl: 'bar.dart'), + SourceLocation(13, sourceUrl: 'bar.dart'), '_'); expect(() => span.compareTo(other), throwsArgumentError); }); }); test('fields work correctly', () { - expect(span.start, equals(SourceLocation(5, sourceUrl: "foo.dart"))); - expect(span.end, equals(SourceLocation(12, sourceUrl: "foo.dart"))); - expect(span.sourceUrl, equals(Uri.parse("foo.dart"))); + expect(span.start, equals(SourceLocation(5, sourceUrl: 'foo.dart'))); + expect(span.end, equals(SourceLocation(12, sourceUrl: 'foo.dart'))); + expect(span.sourceUrl, equals(Uri.parse('foo.dart'))); expect(span.length, equals(7)); }); - group("union()", () { - test("works with a preceding adjacent span", () { - final other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"), - SourceLocation(5, sourceUrl: "foo.dart"), "hey, "); + group('union()', () { + test('works with a preceding adjacent span', () { + final other = SourceSpan(SourceLocation(0, sourceUrl: 'foo.dart'), + SourceLocation(5, sourceUrl: 'foo.dart'), 'hey, '); final result = span.union(other); expect(result.start, equals(other.start)); expect(result.end, equals(span.end)); - expect(result.text, equals("hey, foo bar")); + expect(result.text, equals('hey, foo bar')); }); - test("works with a preceding overlapping span", () { - final other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"), - SourceLocation(8, sourceUrl: "foo.dart"), "hey, foo"); + test('works with a preceding overlapping span', () { + final other = SourceSpan(SourceLocation(0, sourceUrl: 'foo.dart'), + SourceLocation(8, sourceUrl: 'foo.dart'), 'hey, foo'); final result = span.union(other); expect(result.start, equals(other.start)); expect(result.end, equals(span.end)); - expect(result.text, equals("hey, foo bar")); + expect(result.text, equals('hey, foo bar')); }); - test("works with a following adjacent span", () { - final other = SourceSpan(SourceLocation(12, sourceUrl: "foo.dart"), - SourceLocation(16, sourceUrl: "foo.dart"), " baz"); + test('works with a following adjacent span', () { + final other = SourceSpan(SourceLocation(12, sourceUrl: 'foo.dart'), + SourceLocation(16, sourceUrl: 'foo.dart'), ' baz'); final result = span.union(other); expect(result.start, equals(span.start)); expect(result.end, equals(other.end)); - expect(result.text, equals("foo bar baz")); + expect(result.text, equals('foo bar baz')); }); - test("works with a following overlapping span", () { - final other = SourceSpan(SourceLocation(9, sourceUrl: "foo.dart"), - SourceLocation(16, sourceUrl: "foo.dart"), "bar baz"); + test('works with a following overlapping span', () { + final other = SourceSpan(SourceLocation(9, sourceUrl: 'foo.dart'), + SourceLocation(16, sourceUrl: 'foo.dart'), 'bar baz'); final result = span.union(other); expect(result.start, equals(span.start)); expect(result.end, equals(other.end)); - expect(result.text, equals("foo bar baz")); + expect(result.text, equals('foo bar baz')); }); - test("works with an internal overlapping span", () { - final other = SourceSpan(SourceLocation(7, sourceUrl: "foo.dart"), - SourceLocation(10, sourceUrl: "foo.dart"), "o b"); + test('works with an internal overlapping span', () { + 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", () { - final other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"), - SourceLocation(16, sourceUrl: "foo.dart"), "hey, foo bar baz"); + test('works with an external overlapping span', () { + final other = SourceSpan(SourceLocation(0, sourceUrl: 'foo.dart'), + SourceLocation(16, sourceUrl: 'foo.dart'), 'hey, foo bar baz'); expect(span.union(other), equals(other)); }); }); - group("message()", () { - test("prints the text being described", () { - expect(span.message("oh no"), equals(""" + group('message()', () { + test('prints the text being described', () { + expect(span.message('oh no'), equals(""" line 1, column 6 of foo.dart: oh no , 1 | foo bar @@ -191,10 +191,10 @@ line 1, column 6 of foo.dart: oh no '""")); }); - test("gracefully handles a missing source URL", () { - final span = SourceSpan(SourceLocation(5), SourceLocation(12), "foo bar"); + test('gracefully handles a missing source URL', () { + final span = SourceSpan(SourceLocation(5), SourceLocation(12), 'foo bar'); - expect(span.message("oh no"), equalsIgnoringWhitespace(""" + expect(span.message('oh no'), equalsIgnoringWhitespace(""" line 1, column 6: oh no , 1 | foo bar @@ -202,14 +202,14 @@ line 1, column 6: oh no '""")); }); - test("gracefully handles empty text", () { - final span = SourceSpan(SourceLocation(5), SourceLocation(5), ""); + test('gracefully handles empty text', () { + final span = SourceSpan(SourceLocation(5), SourceLocation(5), ''); - expect(span.message("oh no"), equals("line 1, column 6: oh no")); + expect(span.message('oh no'), equals('line 1, column 6: oh no')); }); test("doesn't colorize if color is false", () { - expect(span.message("oh no", color: false), equals(""" + expect(span.message('oh no', color: false), equals(""" line 1, column 6 of foo.dart: oh no , 1 | foo bar @@ -217,8 +217,8 @@ line 1, column 6 of foo.dart: oh no '""")); }); - test("colorizes if color is true", () { - expect(span.message("oh no", color: true), equals(""" + 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} @@ -227,7 +227,7 @@ ${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} @@ -235,14 +235,14 @@ ${colors.blue} |${colors.none} ${colors.yellow}^^^^^^^${colors.none} ${colors.blue} '${colors.none}""")); }); - test("with context, underlines the right column", () { + test('with context, underlines the right column', () { final spanWithContext = SourceSpanWithContext( - SourceLocation(5, sourceUrl: "foo.dart"), - SourceLocation(12, sourceUrl: "foo.dart"), - "foo bar", - "-----foo bar-----"); + 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}----- @@ -251,53 +251,53 @@ ${colors.blue} '${colors.none}""")); }); }); - group("compareTo()", () { - test("sorts by start location first", () { - final other = SourceSpan(SourceLocation(6, sourceUrl: "foo.dart"), - SourceLocation(14, sourceUrl: "foo.dart"), "oo bar b"); + group('compareTo()', () { + test('sorts by start location first', () { + final other = SourceSpan(SourceLocation(6, sourceUrl: 'foo.dart'), + SourceLocation(14, sourceUrl: 'foo.dart'), 'oo bar b'); expect(span.compareTo(other), lessThan(0)); expect(other.compareTo(span), greaterThan(0)); }); - test("sorts by length second", () { - final other = SourceSpan(SourceLocation(5, sourceUrl: "foo.dart"), - SourceLocation(14, sourceUrl: "foo.dart"), "foo bar b"); + test('sorts by length second', () { + final other = SourceSpan(SourceLocation(5, sourceUrl: 'foo.dart'), + SourceLocation(14, sourceUrl: 'foo.dart'), 'foo bar b'); expect(span.compareTo(other), lessThan(0)); expect(other.compareTo(span), greaterThan(0)); }); - test("considers equal spans equal", () { + test('considers equal spans equal', () { expect(span.compareTo(span), equals(0)); }); }); - group("equality", () { - test("two spans with the same locations are equal", () { - final other = SourceSpan(SourceLocation(5, sourceUrl: "foo.dart"), - SourceLocation(12, sourceUrl: "foo.dart"), "foo bar"); + group('equality', () { + test('two spans with the same locations are equal', () { + 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", () { - final other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"), - SourceLocation(12, sourceUrl: "foo.dart"), "hey, foo bar"); + 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", () { - final other = SourceSpan(SourceLocation(5, sourceUrl: "foo.dart"), - SourceLocation(16, sourceUrl: "foo.dart"), "foo bar baz"); + 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", () { - final other = SourceSpan(SourceLocation(5, sourceUrl: "bar.dart"), - SourceLocation(12, sourceUrl: "bar.dart"), "foo bar"); + final other = SourceSpan(SourceLocation(5, sourceUrl: 'bar.dart'), + SourceLocation(12, sourceUrl: 'bar.dart'), 'foo bar'); expect(span, isNot(equals(other))); }); From b41607b1d496b158819cb2141764bc91d24665c0 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Fri, 22 Nov 2019 15:57:23 -0800 Subject: [PATCH 064/128] Fix remaining prefer_single_quotes and fail travis on lints (dart-lang/source_span#48) Missed saving some files in my editor in https://github.com/dart-lang/source_span/pull/47 The travis config was not set to fail for lints. --- pkgs/source_span/.travis.yml | 3 +- pkgs/source_span/lib/source_span.dart | 14 ++--- pkgs/source_span/lib/src/highlighter.dart | 58 ++++++++++---------- pkgs/source_span/lib/src/span.dart | 2 +- pkgs/source_span/lib/src/span_exception.dart | 2 +- pkgs/source_span/lib/src/utils.dart | 2 +- pkgs/source_span/test/file_test.dart | 10 ++-- pkgs/source_span/test/location_test.dart | 28 +++++----- 8 files changed, 60 insertions(+), 59 deletions(-) diff --git a/pkgs/source_span/.travis.yml b/pkgs/source_span/.travis.yml index ace10ab04..edb90e60b 100644 --- a/pkgs/source_span/.travis.yml +++ b/pkgs/source_span/.travis.yml @@ -13,7 +13,8 @@ matrix: - dart: dev dart_task: dartfmt - dart: dev - dart_task: dartanalyzer + dart_task: + dartanalyzer: --fatal-warnings --fatal-infos . # Only building master means that we don't run two builds for each pull request. branches: diff --git a/pkgs/source_span/lib/source_span.dart b/pkgs/source_span/lib/source_span.dart index 6ed10a0e6..534a3a7aa 100644 --- a/pkgs/source_span/lib/source_span.dart +++ b/pkgs/source_span/lib/source_span.dart @@ -2,10 +2,10 @@ // 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. -export "src/file.dart"; -export "src/location.dart"; -export "src/location_mixin.dart"; -export "src/span.dart"; -export "src/span_exception.dart"; -export "src/span_mixin.dart"; -export "src/span_with_context.dart"; +export 'src/file.dart'; +export 'src/location.dart'; +export 'src/location_mixin.dart'; +export 'src/span.dart'; +export 'src/span_exception.dart'; +export 'src/span_mixin.dart'; +export 'src/span_with_context.dart'; diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 94bc85771..f3af75f7e 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -90,7 +90,7 @@ class Highlighter { /// newlines. static SourceSpanWithContext _normalizeNewlines(SourceSpanWithContext span) { final text = span.text; - if (!text.contains("\r\n")) return span; + if (!text.contains('\r\n')) return span; var endOffset = span.end.offset; for (var i = 0; i < text.length - 1; i++) { @@ -105,8 +105,8 @@ class Highlighter { sourceUrl: span.sourceUrl, line: span.end.line, column: span.end.column), - text.replaceAll("\r\n", "\n"), - span.context.replaceAll("\r\n", "\n")); + text.replaceAll('\r\n', '\n'), + span.context.replaceAll('\r\n', '\n')); } /// Normalizes [span] to remove a trailing newline from `span.context`. @@ -115,17 +115,17 @@ class Highlighter { /// the trailing newline used to be. static SourceSpanWithContext _normalizeTrailingNewline( SourceSpanWithContext span) { - if (!span.context.endsWith("\n")) return span; + if (!span.context.endsWith('\n')) return span; // If there's a full blank line on the end of [span.context], it's probably // significant, so we shouldn't trim it. - if (span.text.endsWith("\n\n")) return span; + if (span.text.endsWith('\n\n')) return span; final context = span.context.substring(0, span.context.length - 1); var text = span.text; var start = span.start; var end = span.end; - if (span.text.endsWith("\n") && _isTextAtEndOfContext(span)) { + if (span.text.endsWith('\n') && _isTextAtEndOfContext(span)) { text = span.text.substring(0, span.text.length - 1); end = SourceLocation(span.end.offset - 1, sourceUrl: span.sourceUrl, @@ -163,9 +163,9 @@ class Highlighter { if (text.codeUnitAt(text.length - 1) == $lf) { return text.length == 1 ? 0 - : text.length - text.lastIndexOf("\n", text.length - 2) - 1; + : text.length - text.lastIndexOf('\n', text.length - 2) - 1; } else { - return text.length - text.lastIndexOf("\n") - 1; + return text.length - text.lastIndexOf('\n') - 1; } } @@ -202,11 +202,11 @@ class Highlighter { // [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]. - final 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); - _buffer.write(" " * _paddingAfterSidebar); + _buffer.write(' ' * _paddingAfterSidebar); _writeText(line); _buffer.writeln(); lineNumber++; @@ -214,7 +214,7 @@ class Highlighter { context = context.substring(lineStart); } - final lines = context.split("\n"); + final lines = context.split('\n'); final lastLineIndex = _span.end.line - _span.start.line; if (lines.last.isEmpty && lines.length > lastLineIndex + 1) { @@ -247,16 +247,16 @@ class Highlighter { // 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(" "); + _buffer.write(' '); _colorize(() { - _buffer..write(glyph.glyphOrAscii("┌", "/"))..write(" "); + _buffer..write(glyph.glyphOrAscii('┌', '/'))..write(' '); _writeText(line); }); _buffer.writeln(); return; } - _buffer.write(" " * _paddingAfterSidebar); + _buffer.write(' ' * _paddingAfterSidebar); _writeText(textBefore); final textInside = line.substring(startColumn, endColumn); _colorize(() => _writeText(textInside)); @@ -274,17 +274,17 @@ class Highlighter { // single-line span, and a pointer to the beginning of a multi-line span. _writeSidebar(); if (_multiline) { - _buffer.write(" "); + _buffer.write(' '); _colorize(() { _buffer ..write(glyph.topLeftCorner) ..write(glyph.horizontalLine * (startColumn + 1)) - ..write("^"); + ..write('^'); }); } else { - _buffer.write(" " * (startColumn + 1)); + _buffer.write(' ' * (startColumn + 1)); _colorize( - () => _buffer.write("^" * math.max(endColumn - startColumn, 1))); + () => _buffer.write('^' * math.max(endColumn - startColumn, 1))); } _buffer.writeln(); } @@ -298,9 +298,9 @@ class Highlighter { for (var line in lines) { _writeSidebar(line: lineNumber); - _buffer.write(" "); + _buffer.write(' '); _colorize(() { - _buffer..write(glyph.verticalLine)..write(" "); + _buffer..write(glyph.verticalLine)..write(' '); _writeText(line); }); _buffer.writeln(); @@ -320,19 +320,19 @@ class Highlighter { // If the span covers the entire last line, don't bother pointing out // exactly where it ends. if (_multiline && endColumn == line.length) { - _buffer.write(" "); + _buffer.write(' '); _colorize(() { - _buffer..write(glyph.glyphOrAscii("└", "\\"))..write(" "); + _buffer..write(glyph.glyphOrAscii('└', '\\'))..write(' '); _writeText(line); }); _buffer.writeln(); return; } - _buffer.write(" "); + _buffer.write(' '); final textInside = line.substring(0, endColumn); _colorize(() { - _buffer..write(glyph.verticalLine)..write(" "); + _buffer..write(glyph.verticalLine)..write(' '); _writeText(textInside); }); _writeText(line.substring(endColumn)); @@ -346,12 +346,12 @@ class Highlighter { // Write the highlight for the final line, which is an arrow pointing to the // end of the span. _writeSidebar(); - _buffer.write(" "); + _buffer.write(' '); _colorize(() { _buffer ..write(glyph.bottomLeftCorner) ..write(glyph.horizontalLine * endColumn) - ..write("^"); + ..write('^'); }); _buffer.writeln(); } @@ -362,7 +362,7 @@ class Highlighter { var lineNumber = _span.end.line + 1; for (var line in lines) { _writeSidebar(line: lineNumber); - _buffer.write(" " * _paddingAfterSidebar); + _buffer.write(' ' * _paddingAfterSidebar); _writeText(line); _buffer.writeln(); lineNumber++; @@ -374,7 +374,7 @@ class Highlighter { void _writeText(String text) { for (var char in text.codeUnits) { if (char == $tab) { - _buffer.write(" " * _spacesPerTab); + _buffer.write(' ' * _spacesPerTab); } else { _buffer.writeCharCode(char); } @@ -390,7 +390,7 @@ class Highlighter { // numbers to human-friendly 1-indexed line numbers. _buffer.write((line + 1).toString().padRight(_paddingBeforeSidebar)); } else { - _buffer.write(" " * _paddingBeforeSidebar); + _buffer.write(' ' * _paddingBeforeSidebar); } _buffer.write(end ?? glyph.verticalLine); }, color: colors.blue); diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index 87ce846b0..48dfae73f 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -96,7 +96,7 @@ class SourceSpanBase extends SourceSpanMixin { SourceSpanBase(this.start, this.end, this.text) { if (end.sourceUrl != start.sourceUrl) { - throw ArgumentError("Source URLs \"${start.sourceUrl}\" and " + throw ArgumentError('Source URLs \"${start.sourceUrl}\" and ' " \"${end.sourceUrl}\" don't match."); } else if (end.offset < start.offset) { throw ArgumentError('End $end must come after start $start.'); diff --git a/pkgs/source_span/lib/src/span_exception.dart b/pkgs/source_span/lib/src/span_exception.dart index 2ce0f1a5a..02c897452 100644 --- a/pkgs/source_span/lib/src/span_exception.dart +++ b/pkgs/source_span/lib/src/span_exception.dart @@ -30,7 +30,7 @@ class SourceSpanException implements Exception { @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)}'; } } diff --git a/pkgs/source_span/lib/src/utils.dart b/pkgs/source_span/lib/src/utils.dart index 33791debd..63ff01cb8 100644 --- a/pkgs/source_span/lib/src/utils.dart +++ b/pkgs/source_span/lib/src/utils.dart @@ -31,7 +31,7 @@ int findLineStart(String context, String text, int column) { if (text.isEmpty) { var beginningOfLine = 0; while (true) { - final index = context.indexOf("\n", beginningOfLine); + final index = context.indexOf('\n', beginningOfLine); if (index == -1) { return context.length - beginningOfLine >= column ? beginningOfLine diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index 499f8ef41..91922006d 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/test/file_test.dart @@ -384,23 +384,23 @@ zip zap zop final result = span.expand(other); expect(result.start, equals(span.start)); expect(result.end, equals(other.end)); - expect(result.text, equals("ar baz\nwhiz")); + expect(result.text, equals('ar baz\nwhiz')); }); - test("works with a following overlapping span", () { + test('works with a following overlapping span', () { 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")); + expect(result.text, equals('ar baz\nwhiz')); }); - test("works with an internal overlapping span", () { + test('works with an internal overlapping span', () { final other = file.span(7, 10); expect(span.expand(other), equals(span)); }); - test("works with an external overlapping span", () { + test('works with an external overlapping span', () { final other = file.span(0, 16); expect(span.expand(other), equals(other)); }); diff --git a/pkgs/source_span/test/location_test.dart b/pkgs/source_span/test/location_test.dart index c0e9c0786..c22a148c0 100644 --- a/pkgs/source_span/test/location_test.dart +++ b/pkgs/source_span/test/location_test.dart @@ -8,7 +8,7 @@ import 'package:test/test.dart'; void main() { SourceLocation location; setUp(() { - location = SourceLocation(15, line: 2, column: 6, sourceUrl: "foo.dart"); + location = SourceLocation(15, line: 2, column: 6, sourceUrl: 'foo.dart'); }); group('errors', () { @@ -36,7 +36,7 @@ void main() { }); test('fields work correctly', () { - expect(location.sourceUrl, equals(Uri.parse("foo.dart"))); + expect(location.sourceUrl, equals(Uri.parse('foo.dart'))); expect(location.offset, equals(15)); expect(location.line, equals(2)); expect(location.column, equals(6)); @@ -53,44 +53,44 @@ void main() { }); }); - test("distance returns the absolute distance between locations", () { - final other = SourceLocation(10, sourceUrl: "foo.dart"); + test('distance returns the absolute distance between locations', () { + 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", () { + test('pointSpan returns an empty span at location', () { final span = location.pointSpan(); expect(span.start, equals(location)); expect(span.end, equals(location)); expect(span.text, isEmpty); }); - group("compareTo()", () { - test("sorts by offset", () { - final other = SourceLocation(20, sourceUrl: "foo.dart"); + group('compareTo()', () { + test('sorts by offset', () { + final other = SourceLocation(20, sourceUrl: 'foo.dart'); expect(location.compareTo(other), lessThan(0)); expect(other.compareTo(location), greaterThan(0)); }); - test("considers equal locations equal", () { + test('considers equal locations equal', () { expect(location.compareTo(location), equals(0)); }); }); - group("equality", () { - test("two locations with the same offset and source are equal", () { - final other = SourceLocation(15, sourceUrl: "foo.dart"); + group('equality', () { + test('two locations with the same offset and source are equal', () { + final other = SourceLocation(15, sourceUrl: 'foo.dart'); expect(location, equals(other)); }); test("a different offset isn't equal", () { - final 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", () { - final other = SourceLocation(15, sourceUrl: "bar.dart"); + final other = SourceLocation(15, sourceUrl: 'bar.dart'); expect(location, isNot(equals(other))); }); }); From 373d878aa33cc49964a406d55ebbc4234a42492b Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Wed, 4 Dec 2019 16:34:42 -0800 Subject: [PATCH 065/128] Enable comment_references lint (dart-lang/source_span#50) Change the markdown link style in a few places to work around a bug with the analyzer where links that are split across lines are not recognized correctly. --- pkgs/source_span/analysis_options.yaml | 3 +-- pkgs/source_span/lib/src/highlighter.dart | 5 +++-- pkgs/source_span/lib/src/span.dart | 10 ++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/pkgs/source_span/analysis_options.yaml b/pkgs/source_span/analysis_options.yaml index 929d6fa97..a94bb5062 100644 --- a/pkgs/source_span/analysis_options.yaml +++ b/pkgs/source_span/analysis_options.yaml @@ -27,8 +27,7 @@ linter: - camel_case_types - cancel_subscriptions - cascade_invocations - # Enable once https://github.com/dart-lang/sdk/issues/31761 is fixed - #- comment_references + - comment_references - constant_identifier_names - control_flow_in_finally - directives_ordering diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index f3af75f7e..3ebe0df0c 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -48,12 +48,13 @@ class Highlighter { /// 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 - /// escape](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) that should + /// it indicates an [ANSI terminal color escape][] that should /// be used to highlight the span's text (for example, `"\u001b[31m"` will /// color red). 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. + /// + /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors factory Highlighter(SourceSpan span, {color}) { if (color == true) color = colors.red; if (color == false) color = null; diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index 48dfae73f..f329e372d 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -52,8 +52,7 @@ abstract class SourceSpan implements Comparable { /// Formats [message] in a human-friendly way associated with this span. /// /// [color] may either be a [String], a [bool], or `null`. If it's a string, - /// it indicates an [ANSI terminal color - /// escape](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) that should + /// it indicates an [ANSI terminal color escape][] that should /// be used to highlight the span's text (for example, `"\u001b[31m"` will /// color red). If it's `true`, it indicates that the text should be /// highlighted using the default color. If it's `false` or `null`, it @@ -62,6 +61,8 @@ abstract class SourceSpan implements Comparable { /// This uses the full range of Unicode characters to highlight the source /// span if [glyph.ascii] is `false` (the default), but only uses ASCII /// characters if it's `true`. + /// + /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors String message(String message, {color}); /// Prints the text associated with this span in a user-friendly way. @@ -71,8 +72,7 @@ abstract class SourceSpan implements Comparable { /// isn't a [SourceSpanWithContext], returns an empty string. /// /// [color] may either be a [String], a [bool], or `null`. If it's a string, - /// it indicates an [ANSI terminal color - /// escape](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) that should + /// it indicates an [ANSI terminal color escape][] that should /// be used to highlight the span's text (for example, `"\u001b[31m"` will /// color red). If it's `true`, it indicates that the text should be /// highlighted using the default color. If it's `false` or `null`, it @@ -81,6 +81,8 @@ abstract class SourceSpan implements Comparable { /// This uses the full range of Unicode characters to highlight the source /// span if [glyph.ascii] is `false` (the default), but only uses ASCII /// characters if it's `true`. + /// + /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors String highlight({color}); } From 1aaeb5a83e08c505694128839e8698a24b7c00b0 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Thu, 5 Dec 2019 11:36:57 -0800 Subject: [PATCH 066/128] Fix newly enforced package:pedantic lints (dart-lang/source_span#51) - prefer_if_null_operators --- pkgs/source_span/lib/src/location.dart | 6 +++--- pkgs/source_span/lib/src/location_mixin.dart | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart index 4f69df5b8..93942f05f 100644 --- a/pkgs/source_span/lib/src/location.dart +++ b/pkgs/source_span/lib/src/location.dart @@ -32,7 +32,7 @@ class SourceLocation implements Comparable { /// /// This prints 1-based lines and columns. String get toolString { - final source = sourceUrl == null ? 'unknown source' : sourceUrl; + final source = sourceUrl ?? 'unknown source'; return '$source:${line + 1}:${column + 1}'; } @@ -45,8 +45,8 @@ class SourceLocation implements Comparable { 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 { + line = line ?? 0, + column = column ?? offset { if (offset < 0) { throw RangeError('Offset may not be negative, was $offset.'); } else if (line != null && line < 0) { diff --git a/pkgs/source_span/lib/src/location_mixin.dart b/pkgs/source_span/lib/src/location_mixin.dart index bbb73b49a..a54e363d0 100644 --- a/pkgs/source_span/lib/src/location_mixin.dart +++ b/pkgs/source_span/lib/src/location_mixin.dart @@ -16,7 +16,7 @@ import 'span.dart'; abstract class SourceLocationMixin implements SourceLocation { @override String get toolString { - final source = sourceUrl == null ? 'unknown source' : sourceUrl; + final source = sourceUrl ?? 'unknown source'; return '$source:${line + 1}:${column + 1}'; } From 9ff0d68b4eee3b2b6326f07ced0664bd7a2c97c3 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 14 Jan 2020 19:48:42 -0800 Subject: [PATCH 067/128] Add support for highlighting multiple spans at once (dart-lang/source_span#49) This makes it possible for applications to provide additional context in their span-based messages. Like the existing highlight format, it's heavily inspired by [Rust's error messages][]. [Rust's error messages]: https://blog.rust-lang.org/images/2016-08-09-Errors/new_errors.png For maximal backwards-compatibility, this doesn't change the formatting of any single-span highlights and it uses extension methods rather than adding new methods to existing classes. --- pkgs/source_span/.travis.yml | 2 +- pkgs/source_span/CHANGELOG.md | 8 + pkgs/source_span/analysis_options.yaml | 13 +- pkgs/source_span/lib/src/highlighter.dart | 802 ++++++++++++------ pkgs/source_span/lib/src/span.dart | 72 ++ pkgs/source_span/lib/src/span_exception.dart | 69 +- pkgs/source_span/lib/src/utils.dart | 38 + pkgs/source_span/pubspec.yaml | 6 +- pkgs/source_span/test/highlight_test.dart | 64 +- .../test/multiple_highlight_test.dart | 281 ++++++ pkgs/source_span/test/span_test.dart | 2 +- 11 files changed, 1061 insertions(+), 296 deletions(-) create mode 100644 pkgs/source_span/test/multiple_highlight_test.dart diff --git a/pkgs/source_span/.travis.yml b/pkgs/source_span/.travis.yml index edb90e60b..9738ed50e 100644 --- a/pkgs/source_span/.travis.yml +++ b/pkgs/source_span/.travis.yml @@ -2,7 +2,7 @@ language: dart dart: - dev - - 2.1.0 + - 2.6.0 dart_task: - test: --platform vm,chrome diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 0dfe483b6..014cc4c63 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,11 @@ +# 1.6.0 + +* Add support for highlighting multiple source spans at once, providing more + context for span-based messages. This is exposed through the new APIs + `SourceSpan.highlightMultiple()` and `SourceSpan.messageMultiple()` (both + extension methods), `MultiSourceSpanException`, and + `MultiSourceSpanFormatException`. + # 1.5.6 * Fix padding around line numbers that are powers of 10 in diff --git a/pkgs/source_span/analysis_options.yaml b/pkgs/source_span/analysis_options.yaml index a94bb5062..0ce791169 100644 --- a/pkgs/source_span/analysis_options.yaml +++ b/pkgs/source_span/analysis_options.yaml @@ -2,6 +2,9 @@ include: package:pedantic/analysis_options.yaml analyzer: strong-mode: implicit-casts: false + errors: + # TODO(natebosch): fix and re-enable. + prefer_single_quotes: ignore linter: rules: - always_declare_return_types @@ -26,7 +29,8 @@ linter: - await_only_futures - camel_case_types - cancel_subscriptions - - cascade_invocations + # TODO(natebosch): fix and re-enable. + #- cascade_invocations - comment_references - constant_identifier_names - control_flow_in_finally @@ -59,14 +63,15 @@ linter: - prefer_contains - prefer_equal_for_default_values - prefer_final_fields - - prefer_final_locals + # TODO(natebosch): fix and re-enable. + #- prefer_final_locals - prefer_generic_function_type_aliases - prefer_initializing_formals - - prefer_interpolation_to_compose_strings + # TODO(natebosch): fix and re-enable. + #- 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 diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 3ebe0df0c..feb5594d5 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -5,6 +5,9 @@ import 'dart:math' as math; import 'package:charcode/charcode.dart'; +import 'package:collection/collection.dart'; +import 'package:meta/meta.dart'; +import 'package:path/path.dart' as p; import 'package:term_glyph/term_glyph.dart' as glyph; import 'colors.dart' as colors; @@ -15,25 +18,26 @@ import 'utils.dart'; /// A class for writing a chunk of text with a particular span highlighted. class Highlighter { - /// The span to highlight. - final SourceSpanWithContext _span; + /// The lines to display, including context around the highlighted spans. + final List<_Line> _lines; - /// The color to highlight [_span] within its context, or `null` if the span - /// should not be colored. - final String _color; + /// The color to highlight the primary [_Highlight] within its context, or + /// `null` if it should not be colored. + final String _primaryColor; - /// Whether [_span] covers multiple lines. - final bool _multiline; + /// The color to highlight the secondary [_Highlight]s within their context, + /// or `null` if they should not be colored. + final String _secondaryColor; /// The number of characters before the bar in the sidebar. final int _paddingBeforeSidebar; - // The number of characters between the bar in the sidebar and the text - // being highlighted. - int get _paddingAfterSidebar => - // This is just a space for a single-line span, but for a multi-line span - // needs to accommodate " | ". - _multiline ? 3 : 1; + /// The maximum number of multiline spans that cover any part of a single + /// line in [_lines]. + final int _maxMultilineSpans; + + /// Whether [_lines] includes lines from multiple different files. + final bool _multipleFiles; /// The buffer to which to write the result. final _buffer = StringBuffer(); @@ -44,28 +48,478 @@ class Highlighter { /// alignment. static const _spacesPerTab = 4; - /// Creates a [Highlighter] that will return a message associated with [span] - /// when [highlight] is called. + /// Creates a [Highlighter] that will return a string highlighting [span] + /// within the text of its file 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 escape][] that should - /// be used to highlight the span's text (for example, `"\u001b[31m"` will - /// color red). 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. + /// it indicates an [ANSI terminal color escape][] that should be used to + /// highlight [span]'s text (for example, `"\u001b[31m"` will color red). 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 no color + /// should be used. + /// + /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors + Highlighter(SourceSpan span, {color}) + : this._(_collateLines([_Highlight(span, primary: true)]), () { + if (color == true) return colors.red; + if (color == false) return null; + return color as String; + }(), null); + + /// Creates a [Highlighter] that will return a string highlighting + /// [primarySpan] as well as all the spans in [secondarySpans] within the text + /// of their file when [highlight] is called. + /// + /// Each span has an associated label that will be written alongside it. For + /// [primarySpan] this message is [primaryLabel], and for [secondarySpans] the + /// labels are the map values. + /// + /// If [color] is `true`, this will use [ANSI terminal color escapes][] to + /// highlight the text. The [primarySpan] will be highlighted with + /// [primaryColor] (which defaults to red), and the [secondarySpans] will be + /// highlighted with [secondaryColor] (which defaults to blue). These + /// arguments are ignored if [color] is `false`. /// /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors - factory Highlighter(SourceSpan span, {color}) { - if (color == true) color = colors.red; - if (color == false) color = null; + Highlighter.multiple(SourceSpan primarySpan, String primaryLabel, + Map secondarySpans, + {bool color = false, String primaryColor, String secondaryColor}) + : this._( + _collateLines([ + _Highlight(primarySpan, label: primaryLabel, primary: true), + for (var entry in secondarySpans.entries) + _Highlight(entry.key, label: entry.value) + ]), + color ? (primaryColor ?? colors.red) : null, + color ? (secondaryColor ?? colors.blue) : null); + + Highlighter._(this._lines, this._primaryColor, this._secondaryColor) + : _paddingBeforeSidebar = 1 + + math.max( + // In a purely mathematical world, floor(log10(n)) would give the + // number of digits in n, but floating point errors render that + // unreliable in practice. + (_lines.last.number + 1).toString().length, + // If [_lines] aren't contiguous, we'll write "..." in place of a + // line number. + _contiguous(_lines) ? 0 : 3), + _maxMultilineSpans = _lines + .map((line) => line.highlights + .where((highlight) => isMultiline(highlight.span)) + .length) + .reduce(math.max), + _multipleFiles = !isAllTheSame(_lines.map((line) => line.url)); + + /// Returns whether [lines] contains any adjacent lines from the same source + /// file that aren't adjacent in the original file. + static bool _contiguous(List<_Line> lines) { + for (var i = 0; i < lines.length - 1; i++) { + var thisLine = lines[i]; + var nextLine = lines[i + 1]; + if (thisLine.number + 1 != nextLine.number && + thisLine.url == nextLine.url) { + return false; + } + } + return true; + } + + /// Collect all the source lines from the contexts of all spans in + /// [highlights], and associates them with the highlights that cover them. + static List<_Line> _collateLines(List<_Highlight> highlights) { + var highlightsByUrl = + groupBy(highlights, (highlight) => highlight.span.sourceUrl); + for (var list in highlightsByUrl.values) { + list.sort((highlight1, highlight2) => + highlight1.span.compareTo(highlight2.span)); + } + + return highlightsByUrl.values.expand((highlightsForFile) { + // First, create a list of all the lines in the current file that we have + // context for along with their line numbers. + var lines = <_Line>[]; + for (var highlight in highlightsForFile) { + var context = highlight.span.context; + // If [highlight.span.context] contains lines prior to the one + // [highlight.span.text] appears on, write those first. + var lineStart = findLineStart( + context, highlight.span.text, highlight.span.start.column); + assert(lineStart != null); // enforced by [_normalizeContext] + + var linesBeforeSpan = + '\n'.allMatches(context.substring(0, lineStart)).length; + + var url = highlight.span.sourceUrl; + var lineNumber = highlight.span.start.line - linesBeforeSpan; + for (var line in context.split('\n')) { + // Only add a line if it hasn't already been added for a previous span. + if (lines.isEmpty || lineNumber > lines.last.number) { + lines.add(_Line(line, lineNumber, url)); + } + lineNumber++; + } + } + + // Next, associate each line with each highlights that covers it. + var activeHighlights = <_Highlight>[]; + var highlightIndex = 0; + for (var line in lines) { + activeHighlights.removeWhere((highlight) => + highlight.span.sourceUrl != line.url || + highlight.span.end.line < line.number); + + var oldHighlightLength = activeHighlights.length; + for (var highlight in highlightsForFile.skip(highlightIndex)) { + if (highlight.span.start.line > line.number) break; + if (highlight.span.sourceUrl != line.url) break; + activeHighlights.add(highlight); + } + highlightIndex += activeHighlights.length - oldHighlightLength; + + line.highlights.addAll(activeHighlights); + } + + return lines; + }).toList(); + } + + /// Returns the highlighted span text. + /// + /// This method should only be called once. + String highlight() { + _writeFileStart(_lines.first.url); + + // Each index of this list represents a column after the sidebar that could + // contain a line indicating an active highlight. If it's `null`, that + // column is empty; if it contains a highlight, it should be drawn for that column. + var highlightsByColumn = List<_Highlight>(_maxMultilineSpans); + + for (var i = 0; i < _lines.length; i++) { + var line = _lines[i]; + if (i > 0) { + var lastLine = _lines[i - 1]; + if (lastLine.url != line.url) { + _writeSidebar(end: glyph.upEnd); + _buffer.writeln(); + _writeFileStart(line.url); + } else if (lastLine.number + 1 != line.number) { + _writeSidebar(text: '...'); + _buffer.writeln(); + } + } + + // If a highlight covers the entire first line other than initial + // whitespace, don't bother pointing out exactly where it begins. Iterate + // in reverse so that longer highlights (which are sorted after shorter + // highlights) appear further out, leading to fewer crossed lines. + for (var highlight in line.highlights.reversed) { + if (isMultiline(highlight.span) && + highlight.span.start.line == line.number && + _isOnlyWhitespace( + line.text.substring(0, highlight.span.start.column))) { + replaceFirstNull(highlightsByColumn, highlight); + } + } + + _writeSidebar(line: line.number); + _buffer.write(' '); + _writeMultilineHighlights(line, highlightsByColumn); + if (highlightsByColumn.isNotEmpty) _buffer.write(' '); + + var primary = line.highlights + .firstWhere((highlight) => highlight.isPrimary, orElse: () => null); + if (primary != null) { + _writeHighlightedText( + line.text, + primary.span.start.line == line.number + ? primary.span.start.column + : 0, + primary.span.end.line == line.number + ? primary.span.end.column + : line.text.length, + color: _primaryColor); + } else { + _writeText(line.text); + } + _buffer.writeln(); + + // Always write the primary span's indicator first so that it's right next + // to the highlighted text. + if (primary != null) _writeIndicator(line, primary, highlightsByColumn); + for (var highlight in line.highlights) { + if (highlight.isPrimary) continue; + _writeIndicator(line, highlight, highlightsByColumn); + } + } + + _writeSidebar(end: glyph.upEnd); + return _buffer.toString(); + } + + /// Writes the beginning of the file highlight for the file with the given + /// [url]. + void _writeFileStart(Uri url) { + if (!_multipleFiles || url == null) { + _writeSidebar(end: glyph.downEnd); + } else { + _writeSidebar(end: glyph.topLeftCorner); + _colorize(() => _buffer.write("${glyph.horizontalLine * 2}>"), + color: colors.blue); + _buffer.write(" ${p.prettyUri(url)}"); + } + _buffer.writeln(); + } + + /// Writes the post-sidebar highlight bars for [line] according to + /// [highlightsByColumn]. + /// + /// If [current] is passed, it's the highlight for which an indicator is being + /// written. If it appears in [highlightsByColumn], a horizontal line is + /// written from its column to the rightmost column. + void _writeMultilineHighlights( + _Line line, List<_Highlight> highlightsByColumn, + {_Highlight current}) { + // Whether we've written a sidebar indicator for opening a new span on this + // line, and which color should be used for that indicator's rightward line. + var openedOnThisLine = false; + String openedOnThisLineColor; + + var currentColor = current == null + ? null + : current.isPrimary ? _primaryColor : _secondaryColor; + var foundCurrent = false; + for (var highlight in highlightsByColumn) { + var startLine = highlight?.span?.start?.line; + var endLine = highlight?.span?.end?.line; + if (current != null && highlight == current) { + foundCurrent = true; + assert(startLine == line.number || endLine == line.number); + _colorize(() { + _buffer.write(startLine == line.number + ? glyph.topLeftCorner + : glyph.bottomLeftCorner); + }, color: currentColor); + } else if (foundCurrent) { + _colorize(() { + _buffer.write(highlight == null ? glyph.horizontalLine : glyph.cross); + }, color: currentColor); + } else if (highlight == null) { + if (openedOnThisLine) { + _colorize(() => _buffer.write(glyph.horizontalLine), + color: openedOnThisLineColor); + } else { + _buffer.write(' '); + } + } else { + _colorize(() { + var vertical = openedOnThisLine ? glyph.cross : glyph.verticalLine; + if (current != null) { + _buffer.write(vertical); + } else if (startLine == line.number) { + _colorize(() { + _buffer + .write(glyph.glyphOrAscii(openedOnThisLine ? '┬' : '┌', '/')); + }, color: openedOnThisLineColor); + openedOnThisLine = true; + openedOnThisLineColor ??= + highlight.isPrimary ? _primaryColor : _secondaryColor; + } else if (endLine == line.number && + highlight.span.end.column == line.text.length) { + _buffer.write(highlight.label == null + ? glyph.glyphOrAscii('└', '\\') + : vertical); + } else { + _colorize(() { + _buffer.write(vertical); + }, color: openedOnThisLineColor); + } + }, color: highlight.isPrimary ? _primaryColor : _secondaryColor); + } + } + } + + // Writes [text], with text between [startColumn] and [endColumn] colorized in + // the same way as [_colorize]. + void _writeHighlightedText(String text, int startColumn, int endColumn, + {@required String color}) { + _writeText(text.substring(0, startColumn)); + _colorize(() => _writeText(text.substring(startColumn, endColumn)), + color: color); + _writeText(text.substring(endColumn, text.length)); + } + + /// Writes an indicator for where [highlight] starts, ends, or both below + /// [line]. + /// + /// This may either add or remove [highlight] from [highlightsByColumn]. + void _writeIndicator( + _Line line, _Highlight highlight, List<_Highlight> highlightsByColumn) { + var color = highlight.isPrimary ? _primaryColor : _secondaryColor; + if (!isMultiline(highlight.span)) { + _writeSidebar(); + _buffer.write(' '); + _writeMultilineHighlights(line, highlightsByColumn, current: highlight); + if (highlightsByColumn.isNotEmpty) _buffer.write(' '); + + _colorize(() { + _writeUnderline(line, highlight.span, + highlight.isPrimary ? "^" : glyph.horizontalLineBold); + _writeLabel(highlight.label); + }, color: color); + _buffer.writeln(); + } else if (highlight.span.start.line == line.number) { + if (highlightsByColumn.contains(highlight)) return; + replaceFirstNull(highlightsByColumn, highlight); + + _writeSidebar(); + _buffer.write(' '); + _writeMultilineHighlights(line, highlightsByColumn, current: highlight); + _colorize(() => _writeArrow(line, highlight.span.start.column), + color: color); + _buffer.writeln(); + } else if (highlight.span.end.line == line.number) { + var coversWholeLine = highlight.span.end.column == line.text.length; + if (coversWholeLine && highlight.label == null) { + replaceWithNull(highlightsByColumn, highlight); + return; + } + + _writeSidebar(); + _buffer.write(' '); + _writeMultilineHighlights(line, highlightsByColumn, current: highlight); + + _colorize(() { + if (coversWholeLine) { + _buffer.write(glyph.horizontalLine * 3); + } else { + _writeArrow(line, math.max(highlight.span.end.column - 1, 0), + beginning: false); + } + _writeLabel(highlight.label); + }, color: color); + _buffer.writeln(); + replaceWithNull(highlightsByColumn, highlight); + } + } + + /// Underlines the portion of [line] covered by [span] with repeated instances + /// of [character]. + void _writeUnderline(_Line line, SourceSpan span, String character) { + assert(!isMultiline(span)); + assert(line.text.contains(span.text)); + + var startColumn = span.start.column; + var endColumn = span.end.column; + + // Adjust the start and end columns to account for any tabs that were + // converted to spaces. + var tabsBefore = _countTabs(line.text.substring(0, startColumn)); + var tabsInside = _countTabs(line.text.substring(startColumn, endColumn)); + startColumn += tabsBefore * (_spacesPerTab - 1); + endColumn += (tabsBefore + tabsInside) * (_spacesPerTab - 1); + + _buffer.write(" " * startColumn); + _buffer.write(character * math.max(endColumn - startColumn, 1)); + } + + /// Write an arrow pointing to column [column] in [line]. + /// + /// If the arrow points to a tab character, this will point to the beginning + /// of the tab if [beginning] is `true` and the end if it's `false`. + void _writeArrow(_Line line, int column, {bool beginning = true}) { + var tabs = _countTabs(line.text.substring(0, column + (beginning ? 0 : 1))); + _buffer + ..write(glyph.horizontalLine * (1 + column + tabs * (_spacesPerTab - 1))) + ..write("^"); + } + + /// Writes a space followed by [label] if [label] isn't `null`. + void _writeLabel(String label) { + if (label != null) _buffer.write(" $label"); + } + + /// Writes a snippet from the source text, converting hard tab characters into + /// plain indentation. + void _writeText(String text) { + for (var char in text.codeUnits) { + if (char == $tab) { + _buffer.write(' ' * _spacesPerTab); + } else { + _buffer.writeCharCode(char); + } + } + } - var newSpan = _normalizeContext(span); - newSpan = _normalizeNewlines(newSpan); - newSpan = _normalizeTrailingNewline(newSpan); - newSpan = _normalizeEndOfLine(newSpan); + // Writes a sidebar to [buffer] that includes [line] as the line number if + // given and writes [end] at the end (defaults to [glyphs.verticalLine]). + // + // If [text] is given, it's used in place of the line number. It can't be + // passed at the same time as [line]. + void _writeSidebar({int line, String text, String end}) { + assert(line == null || text == null); + + // Add 1 to line to convert from computer-friendly 0-indexed line numbers to + // human-friendly 1-indexed line numbers. + if (line != null) text = (line + 1).toString(); + _colorize(() { + _buffer.write((text ?? '').padRight(_paddingBeforeSidebar)); + _buffer.write(end ?? glyph.verticalLine); + }, color: colors.blue); + } - return Highlighter._(newSpan, color as String); + /// Returns the number of hard tabs in [text]. + int _countTabs(String text) { + var count = 0; + for (var char in text.codeUnits) { + if (char == $tab) count++; + } + return count; + } + + /// Returns whether [text] contains only space or tab characters. + bool _isOnlyWhitespace(String text) { + for (var char in text.codeUnits) { + if (char != $space && char != $tab) return false; + } + return true; + } + + /// Colors all text written to [_buffer] during [callback], if colorization is + /// enabled and [color] is not `null`. + void _colorize(void Function() callback, {@required String color}) { + if (_primaryColor != null && color != null) _buffer.write(color); + callback(); + if (_primaryColor != null && color != null) _buffer.write(colors.none); } +} + +/// Information about how to highlight a single section of a source file. +class _Highlight { + /// The section of the source file to highlight. + /// + /// This is normalized to make it easier for [Highlighter] to work with. + final SourceSpanWithContext span; + + /// Whether this is the primary span in the highlight. + /// + /// The primary span is highlighted with a different character and colored + /// differently than non-primary spans. + final bool isPrimary; + + /// The label to include inline when highlighting [span]. + /// + /// This helps distinguish clarify what each highlight means when multiple are + /// used in the same message. + final String label; + + _Highlight(SourceSpan span, {this.label, bool primary = false}) + : span = (() { + var newSpan = _normalizeContext(span); + newSpan = _normalizeNewlines(newSpan); + newSpan = _normalizeTrailingNewline(newSpan); + return _normalizeEndOfLine(newSpan); + })(), + isPrimary = primary; /// Normalizes [span] to ensure that it's a [SourceSpanWithContext] whose /// context actually contains its text at the expected column. @@ -128,11 +582,15 @@ class Highlighter { var end = span.end; if (span.text.endsWith('\n') && _isTextAtEndOfContext(span)) { text = span.text.substring(0, span.text.length - 1); - end = SourceLocation(span.end.offset - 1, - sourceUrl: span.sourceUrl, - line: span.end.line - 1, - column: _lastLineLength(text)); - start = span.start.offset == span.end.offset ? end : span.start; + if (text.isEmpty) { + end = start; + } else { + end = SourceLocation(span.end.offset - 1, + sourceUrl: span.sourceUrl, + line: span.end.line - 1, + column: _lastLineLength(context)); + start = span.start.offset == span.end.offset ? end : span.start; + } } return SourceSpanWithContext(start, end, text, context); } @@ -150,18 +608,21 @@ class Highlighter { SourceLocation(span.end.offset - 1, sourceUrl: span.sourceUrl, line: span.end.line - 1, - column: _lastLineLength(text)), + column: text.length - text.lastIndexOf('\n') - 1), text, - span.context); + // If the context also ends with a newline, it's possible that we don't + // have the full context for that line, so we shouldn't print it at all. + span.context.endsWith("\n") + ? span.context.substring(0, span.context.length - 1) + : span.context); } /// Returns the length of the last line in [text], whether or not it ends in a /// newline. static int _lastLineLength(String text) { - if (text.isEmpty) return 0; - - // The "- 1" here avoids counting the newline itself. - if (text.codeUnitAt(text.length - 1) == $lf) { + if (text.isEmpty) { + return 0; + } else if (text.codeUnitAt(text.length - 1) == $lf) { return text.length == 1 ? 0 : text.length - text.lastIndexOf('\n', text.length - 2) - 1; @@ -177,250 +638,35 @@ class Highlighter { span.length == span.context.length; - Highlighter._(this._span, this._color) - : _multiline = _span.start.line != _span.end.line, - // In a purely mathematical world, floor(log10(n)) would give the number of - // digits in n, but floating point errors render that unreliable in - // practice. - _paddingBeforeSidebar = (_span.end.line + 1).toString().length + 1; - - /// Returns the highlighted span text. - /// - /// This method should only be called once. - String highlight() { - _writeSidebar(end: glyph.downEnd); - _buffer.writeln(); - - // If [_span.context] contains lines prior to the one [_span.text] appears - // on, write those first. - final lineStart = - findLineStart(_span.context, _span.text, _span.start.column); - assert(lineStart != null); // enforced by [_normalizeContext] - - var context = _span.context; - if (lineStart > 0) { - // Take a substring to one character *before* [lineStart] because - // [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]. - final lines = context.substring(0, lineStart - 1).split('\n'); - var lineNumber = _span.start.line - lines.length; - for (var line in lines) { - _writeSidebar(line: lineNumber); - _buffer.write(' ' * _paddingAfterSidebar); - _writeText(line); - _buffer.writeln(); - lineNumber++; - } - context = context.substring(lineStart); - } - - final lines = context.split('\n'); - - 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. - lines.removeLast(); - } - - _writeFirstLine(lines.first); - if (_multiline) { - _writeIntermediateLines(lines.skip(1).take(lastLineIndex - 1)); - _writeLastLine(lines[lastLineIndex]); - } - _writeTrailingLines(lines.skip(lastLineIndex + 1)); - - _writeSidebar(end: glyph.upEnd); - - return _buffer.toString(); - } - - // Writes the first (and possibly only) line highlighted by the span. - void _writeFirstLine(String line) { - _writeSidebar(line: _span.start.line); - - var startColumn = math.min(_span.start.column, line.length); - var endColumn = math.min( - startColumn + _span.end.offset - _span.start.offset, line.length); - 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('┌', '/'))..write(' '); - _writeText(line); - }); - _buffer.writeln(); - return; - } - - _buffer.write(' ' * _paddingAfterSidebar); - _writeText(textBefore); - 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. - final tabsBefore = _countTabs(textBefore); - final tabsInside = _countTabs(textInside); - startColumn = startColumn + tabsBefore * (_spacesPerTab - 1); - endColumn = endColumn + (tabsBefore + tabsInside) * (_spacesPerTab - 1); - - // Write the highlight for the first line. This is a series of carets for a - // single-line span, and a pointer to the beginning of a multi-line span. - _writeSidebar(); - if (_multiline) { - _buffer.write(' '); - _colorize(() { - _buffer - ..write(glyph.topLeftCorner) - ..write(glyph.horizontalLine * (startColumn + 1)) - ..write('^'); - }); - } else { - _buffer.write(' ' * (startColumn + 1)); - _colorize( - () => _buffer.write('^' * math.max(endColumn - startColumn, 1))); - } - _buffer.writeln(); - } - - /// Writes the lines between the first and last lines highlighted by the span. - void _writeIntermediateLines(Iterable lines) { - assert(_multiline); - - // +1 because the first line was already written. - var lineNumber = _span.start.line + 1; - for (var line in lines) { - _writeSidebar(line: lineNumber); - - _buffer.write(' '); - _colorize(() { - _buffer..write(glyph.verticalLine)..write(' '); - _writeText(line); - }); - _buffer.writeln(); - - lineNumber++; - } - } - - // Writes the last line highlighted by the span. - void _writeLastLine(String line) { - assert(_multiline); - - _writeSidebar(line: _span.end.line); - - var endColumn = math.min(_span.end.column, line.length); - - // If the span covers the entire last line, don't bother pointing out - // exactly where it ends. - if (_multiline && endColumn == line.length) { - _buffer.write(' '); - _colorize(() { - _buffer..write(glyph.glyphOrAscii('└', '\\'))..write(' '); - _writeText(line); - }); - _buffer.writeln(); - return; - } - - _buffer.write(' '); - final textInside = line.substring(0, endColumn); - _colorize(() { - _buffer..write(glyph.verticalLine)..write(' '); - _writeText(textInside); - }); - _writeText(line.substring(endColumn)); - _buffer.writeln(); - - // Adjust the end column to account for any tabs that were converted to - // spaces. - final tabsInside = _countTabs(textInside); - endColumn = endColumn + tabsInside * (_spacesPerTab - 1); - - // Write the highlight for the final line, which is an arrow pointing to the - // end of the span. - _writeSidebar(); - _buffer.write(' '); - _colorize(() { - _buffer - ..write(glyph.bottomLeftCorner) - ..write(glyph.horizontalLine * endColumn) - ..write('^'); - }); - _buffer.writeln(); + @override + String toString() { + var buffer = StringBuffer(); + if (isPrimary) buffer.write("primary "); + buffer.write("${span.start.line}:${span.start.column}-" + "${span.end.line}:${span.end.column}"); + if (label != null) buffer.write(" ($label)"); + return buffer.toString(); } +} - /// Writes lines that appear in the context string but come after the span. - void _writeTrailingLines(Iterable lines) { - // +1 because this comes after any lines covered by the span. - var lineNumber = _span.end.line + 1; - for (var line in lines) { - _writeSidebar(line: lineNumber); - _buffer.write(' ' * _paddingAfterSidebar); - _writeText(line); - _buffer.writeln(); - lineNumber++; - } - } +/// A single line of the source file being highlighted. +class _Line { + /// The text of the line, not including the trailing newline. + final String text; - /// Writes a snippet from the source text, converting hard tab characters into - /// plain indentation. - void _writeText(String text) { - for (var char in text.codeUnits) { - if (char == $tab) { - _buffer.write(' ' * _spacesPerTab); - } else { - _buffer.writeCharCode(char); - } - } - } + /// The 0-based line number in the source file. + final int number; - // Writes a sidebar to [buffer] that includes [line] as the line number if - // given and writes [end] at the end (defaults to [glyphs.verticalLine]). - void _writeSidebar({int line, String end}) { - _colorize(() { - if (line != null) { - // Add 1 to line to convert from computer-friendly 0-indexed line - // numbers to human-friendly 1-indexed line numbers. - _buffer.write((line + 1).toString().padRight(_paddingBeforeSidebar)); - } else { - _buffer.write(' ' * _paddingBeforeSidebar); - } - _buffer.write(end ?? glyph.verticalLine); - }, color: colors.blue); - } + /// The URL of the source file in which this line appears. + final Uri url; - /// Returns the number of hard tabs in [text]. - int _countTabs(String text) { - var count = 0; - for (var char in text.codeUnits) { - if (char == $tab) count++; - } - return count; - } + /// All highlights that cover any portion of this line, in source span order. + /// + /// This is populated after the initial line is created. + final highlights = <_Highlight>[]; - /// Returns whether [text] contains only space or tab characters. - bool _isOnlyWhitespace(String text) { - for (var char in text.codeUnits) { - if (char != $space && char != $tab) return false; - } - return true; - } + _Line(this.text, this.number, this.url); - /// Colors all text written to [_buffer] during [callback], if colorization is - /// enabled. - /// - /// If [color] is passed, it's used as the color; otherwise, [_color] is used. - void _colorize(void Function() callback, {String color}) { - if (_color != null) _buffer.write(color ?? _color); - callback(); - if (_color != null) _buffer.write(colors.none); - } + @override + String toString() => '$number: "$text" (${highlights.join(', ')})'; } diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index f329e372d..51e81ab80 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -2,8 +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:path/path.dart' as p; import 'package:term_glyph/term_glyph.dart' as glyph; +import 'file.dart'; +import 'highlighter.dart'; import 'location.dart'; import 'span_mixin.dart'; import 'span_with_context.dart'; @@ -108,3 +111,72 @@ class SourceSpanBase extends SourceSpanMixin { } } } + +// TODO(#52): Move these to instance methods in the next breaking release. +/// Extension methods on the base [SourceSpan] API. +extension SourceSpanExtension on SourceSpan { + /// Like [SourceSpan.message], but also highlights [secondarySpans] to provide + /// the user with additional context. + /// + /// Each span takes a label ([label] for this span, and the values of the + /// [secondarySpans] map for the secondary spans) that's used to indicate to + /// the user what that particular span represents. + /// + /// If [color] is `true`, [ANSI terminal color escapes][] are used to color + /// the resulting string. By default this span is colored red and the + /// secondary spans are colored blue, but that can be customized by passing + /// ANSI escape strings to [primaryColor] or [secondaryColor]. + /// + /// [ANSI terminal color escapes]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors + /// + /// Each span in [secondarySpans] must refer to the same document as this + /// span. Throws an [ArgumentError] if any secondary span has a different + /// source URL than this span. + /// + /// Note that while this will work with plain [SourceSpan]s, it will produce + /// much more useful output with [SourceSpanWithContext]s (including + /// [FileSpan]s). + String messageMultiple( + String message, String label, Map secondarySpans, + {bool color = false, String primaryColor, String secondaryColor}) { + final buffer = StringBuffer() + ..write('line ${start.line + 1}, column ${start.column + 1}'); + if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}'); + buffer + ..writeln(': $message') + ..write(highlightMultiple(label, secondarySpans, + color: color, + primaryColor: primaryColor, + secondaryColor: secondaryColor)); + return buffer.toString(); + } + + /// Like [SourceSpan.highlight], but also highlights [secondarySpans] to + /// provide the user with additional context. + /// + /// Each span takes a label ([label] for this span, and the values of the + /// [secondarySpans] map for the secondary spans) that's used to indicate to + /// the user what that particular span represents. + /// + /// If [color] is `true`, [ANSI terminal color escapes][] are used to color + /// the resulting string. By default this span is colored red and the + /// secondary spans are colored blue, but that can be customized by passing + /// ANSI escape strings to [primaryColor] or [secondaryColor]. + /// + /// [ANSI terminal color escapes]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors + /// + /// Each span in [secondarySpans] must refer to the same document as this + /// span. Throws an [ArgumentError] if any secondary span has a different + /// source URL than this span. + /// + /// Note that while this will work with plain [SourceSpan]s, it will produce + /// much more useful output with [SourceSpanWithContext]s (including + /// [FileSpan]s). + String highlightMultiple(String label, Map secondarySpans, + {bool color = false, String primaryColor, String secondaryColor}) => + Highlighter.multiple(this, label, secondarySpans, + color: color, + primaryColor: primaryColor, + secondaryColor: secondaryColor) + .highlight(); +} diff --git a/pkgs/source_span/lib/src/span_exception.dart b/pkgs/source_span/lib/src/span_exception.dart index 02c897452..5b33d06ec 100644 --- a/pkgs/source_span/lib/src/span_exception.dart +++ b/pkgs/source_span/lib/src/span_exception.dart @@ -37,7 +37,6 @@ class SourceSpanException implements Exception { /// A [SourceSpanException] that's also a [FormatException]. class SourceSpanFormatException extends SourceSpanException implements FormatException { - // This is a getter so that subclasses can override it. @override final dynamic source; @@ -47,3 +46,71 @@ class SourceSpanFormatException extends SourceSpanException SourceSpanFormatException(String message, SourceSpan span, [this.source]) : super(message, span); } + +/// A [SourceSpanException] that also highlights some secondary spans to provide +/// the user with extra context. +/// +/// Each span has a label ([primaryLabel] for the primary, and the values of the +/// [secondarySpans] map for the secondary spans) that's used to indicate to the +/// user what that particular span represents. +class MultiSourceSpanException extends SourceSpanException { + /// A label to attach to [span] that provides additional information and helps + /// distinguish it from [secondarySpans]. + final String primaryLabel; + + /// A map whose keys are secondary spans that should be highlighted. + /// + /// Each span's value is a label to attach to that span that provides + /// additional information and helps distinguish it from [secondarySpans]. + final Map secondarySpans; + + MultiSourceSpanException(String message, SourceSpan span, this.primaryLabel, + Map secondarySpans) + : secondarySpans = Map.unmodifiable(secondarySpans), + super(message, span); + + /// Returns a string representation of `this`. + /// + /// [color] may either be a [String], a [bool], or `null`. If it's a string, + /// it indicates an ANSI terminal color escape that should be used to + /// highlight the primary 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. + /// + /// If [color] is `true` or a string, [secondaryColor] is used to highlight + /// [secondarySpans]. + @override + String toString({color, String secondaryColor}) { + if (span == null) return message; + + var useColor = false; + String primaryColor; + if (color is String) { + useColor = true; + primaryColor = color; + } else if (color == true) { + useColor = true; + } + + return "Error on " + + span.messageMultiple(message, primaryLabel, secondarySpans, + color: useColor, + primaryColor: primaryColor, + secondaryColor: secondaryColor); + } +} + +/// A [MultiSourceSpanException] that's also a [FormatException]. +class MultiSourceSpanFormatException extends MultiSourceSpanException + implements FormatException { + @override + final dynamic source; + + @override + int get offset => span?.start?.offset; + + MultiSourceSpanFormatException(String message, SourceSpan span, + String primaryLabel, Map secondarySpans, + [this.source]) + : super(message, span, primaryLabel, secondarySpans); +} diff --git a/pkgs/source_span/lib/src/utils.dart b/pkgs/source_span/lib/src/utils.dart index 63ff01cb8..12b15b382 100644 --- a/pkgs/source_span/lib/src/utils.dart +++ b/pkgs/source_span/lib/src/utils.dart @@ -2,6 +2,8 @@ // 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 'span.dart'; + /// Returns the minimum of [obj1] and [obj2] according to /// [Comparable.compareTo]. T min(T obj1, T obj2) => @@ -12,6 +14,42 @@ T min(T obj1, T obj2) => T max(T obj1, T obj2) => obj1.compareTo(obj2) > 0 ? obj1 : obj2; +/// Returns whether all elements of [iter] are the same value, according to +/// `==`. +/// +/// Assumes [iter] doesn't contain any `null` values. +bool isAllTheSame(Iterable iter) { + Object lastValue; + for (var value in iter) { + if (lastValue == null) { + lastValue = value; + } else if (value != lastValue) { + return false; + } + } + return true; +} + +/// Returns whether [span] covers multiple lines. +bool isMultiline(SourceSpan span) => span.start.line != span.end.line; + +/// Sets the first `null` element of [list] to [element]. +void replaceFirstNull(List list, E element) { + var index = list.indexOf(null); + if (index < 0) throw ArgumentError("$list contains no null elements."); + list[index] = element; +} + +/// Sets the element of [list] that currently contains [element] to `null`. +void replaceWithNull(List list, E element) { + var index = list.indexOf(element); + if (index < 0) { + throw ArgumentError("$list contains no elements matching $element."); + } + + list[index] = null; +} + /// Returns the number of instances of [codeUnit] in [string]. int countCodeUnits(String string, int codeUnit) { var count = 0; diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 71e10f60a..2054423d5 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,15 +1,17 @@ name: source_span -version: 1.5.6-dev +version: 1.6.0 description: A library for identifying source spans and locations. author: Dart Team homepage: https://github.com/dart-lang/source_span environment: - sdk: '>=2.1.0 <3.0.0' + sdk: '>=2.6.0 <3.0.0' dependencies: charcode: ^1.0.0 + collection: ^1.8.0 + meta: '>=0.9.0 <2.0.0' path: '>=1.2.0 <2.0.0' term_glyph: ^1.0.0 diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index 9d95b21ef..6313108e1 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -140,6 +140,14 @@ zip zap zop '""")); }); + test('highlights text including a trailing newline', () { + expect(file.span(8, 12).highlight(), equals(""" + , +1 | foo bar baz + | ^^^ + '""")); + }); + test('highlights a single empty line', () { expect( SourceFile.fromString('foo\n\nbar').span(4, 5).highlight(), equals(""" @@ -149,6 +157,14 @@ zip zap zop '""")); }); + test('highlights a trailing newline', () { + expect(file.span(11, 12).highlight(), equals(""" + , +1 | foo bar baz + | ^ + '""")); + }); + group('with a multiline span', () { test('highlights the middle of the first and last lines', () { expect(file.span(4, 34).highlight(), equals(""" @@ -383,6 +399,21 @@ whiz bang boom '""")); }); + test('at the beginning of the first highlighted line', () { + final span = SourceFile.fromString(''' +foo bar\tbaz +whiz bang boom +''').span(7, 21); + + expect(span.highlight(), equals(""" + , +1 | foo bar baz + | ,--------^ +2 | | whiz bang boom + | '---------^ + '""")); + }); + test('within a middle highlighted line', () { final span = SourceFile.fromString(''' foo bar baz @@ -415,6 +446,21 @@ whiz\tbang boom '""")); }); + test('at the end of the last highlighted line', () { + final span = SourceFile.fromString(''' +foo bar baz +whiz\tbang boom +''').span(4, 17); + + expect(span.highlight(), equals(""" + , +1 | foo bar baz + | ,-----^ +2 | | whiz bang boom + | '--------^ + '""")); + }); + test('after the highlighted section', () { final span = SourceFile.fromString(''' foo bar baz @@ -498,7 +544,7 @@ whiz bang\tboom 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.red} ^^^${colors.none} ${colors.blue} '${colors.none}''')); }); @@ -506,7 +552,7 @@ ${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} ${colors.yellow} ^^^${colors.none} ${colors.blue} '${colors.none}''')); }); @@ -514,19 +560,19 @@ ${colors.blue} '${colors.none}''')); 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.red},${colors.none}${colors.red}-----^${colors.none} +${colors.blue}2 |${colors.none} ${colors.red}|${colors.none} ${colors.red}whiz bang boom${colors.none} +${colors.blue}3 |${colors.none} ${colors.red}|${colors.none} ${colors.red}zip zap${colors.none} zop +${colors.blue} |${colors.none} ${colors.red}'${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}1 |${colors.none} ${colors.red}/${colors.none} ${colors.red}foo bar baz${colors.none} +${colors.blue}2 |${colors.none} ${colors.red}|${colors.none} ${colors.red}whiz bang boom${colors.none} +${colors.blue}3 |${colors.none} ${colors.red}\\${colors.none} ${colors.red}zip zap zop${colors.none} ${colors.blue} '${colors.none}''')); }); }); diff --git a/pkgs/source_span/test/multiple_highlight_test.dart b/pkgs/source_span/test/multiple_highlight_test.dart new file mode 100644 index 000000000..f0cceedef --- /dev/null +++ b/pkgs/source_span/test/multiple_highlight_test.dart @@ -0,0 +1,281 @@ +// Copyright (c) 2019, 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 'package:term_glyph/term_glyph.dart' as glyph; +import 'package:test/test.dart'; + +void main() { + bool oldAscii; + setUpAll(() { + oldAscii = glyph.ascii; + glyph.ascii = true; + }); + + tearDownAll(() { + glyph.ascii = oldAscii; + }); + + SourceFile file; + setUp(() { + file = SourceFile.fromString(''' +foo bar baz +whiz bang boom +zip zap zop +fwee fwoo fwip +argle bargle boo +gibble bibble bop +''', url: "file1.txt"); + }); + + test("highlights spans on separate lines", () { + expect( + file.span(17, 21).highlightMultiple( + "one", {file.span(31, 34): "two", file.span(4, 7): "three"}), + equals(""" + , +1 | foo bar baz + | === three +2 | whiz bang boom + | ^^^^ one +3 | zip zap zop + | === two + '""")); + }); + + test("highlights spans on the same line", () { + expect( + file.span(17, 21).highlightMultiple( + "one", {file.span(22, 26): "two", file.span(12, 16): "three"}), + equals(""" + , +2 | whiz bang boom + | ^^^^ one + | ==== three + | ==== two + '""")); + }); + + test("highlights overlapping spans on the same line", () { + expect( + file.span(17, 21).highlightMultiple( + "one", {file.span(20, 26): "two", file.span(12, 18): "three"}), + equals(""" + , +2 | whiz bang boom + | ^^^^ one + | ====== three + | ====== two + '""")); + }); + + test("highlights multiple multiline spans", () { + expect( + file.span(27, 54).highlightMultiple( + "one", {file.span(54, 89): "two", file.span(0, 27): "three"}), + equals(""" + , +1 | / foo bar baz +2 | | whiz bang boom + | '--- three +3 | / zip zap zop +4 | | fwee fwoo fwip + | '--- one +5 | / argle bargle boo +6 | | gibble bibble bop + | '--- two + '""")); + }); + + test("highlights multiple overlapping multiline spans", () { + expect( + file.span(12, 70).highlightMultiple( + "one", {file.span(54, 89): "two", file.span(0, 27): "three"}), + equals(""" + , +1 | /- foo bar baz +2 | |/ whiz bang boom + | '+--- three +3 | | zip zap zop +4 | | fwee fwoo fwip +5 | /+ argle bargle boo + | |'--- one +6 | | gibble bibble bop + | '---- two + '""")); + }); + + test("highlights many layers of overlaps", () { + expect( + file.span(0, 54).highlightMultiple("one", { + file.span(12, 77): "two", + file.span(27, 84): "three", + file.span(39, 88): "four" + }), + equals(""" + , +1 | /--- foo bar baz +2 | |/-- whiz bang boom +3 | ||/- zip zap zop +4 | |||/ fwee fwoo fwip + | '+++--- one +5 | ||| argle bargle boo +6 | ||| gibble bibble bop + | '++------^ two + | '+-------------^ three + | '--- four + '""")); + }); + + group("highlights a multiline span that's a subset", () { + test("with no first or last line overlap", () { + expect( + file + .span(27, 53) + .highlightMultiple("inner", {file.span(12, 70): "outer"}), + equals(""" + , +2 | /- whiz bang boom +3 | |/ zip zap zop +4 | || fwee fwoo fwip + | |'--- inner +5 | | argle bargle boo + | '---- outer + '""")); + }); + + test("overlapping the whole first line", () { + expect( + file + .span(12, 53) + .highlightMultiple("inner", {file.span(12, 70): "outer"}), + equals(""" + , +2 | // whiz bang boom +3 | || zip zap zop +4 | || fwee fwoo fwip + | |'--- inner +5 | | argle bargle boo + | '---- outer + '""")); + }); + + test("overlapping part of first line", () { + expect( + file + .span(17, 53) + .highlightMultiple("inner", {file.span(12, 70): "outer"}), + equals(""" + , +2 | /- whiz bang boom + | |,------^ +3 | || zip zap zop +4 | || fwee fwoo fwip + | |'--- inner +5 | | argle bargle boo + | '---- outer + '""")); + }); + + test("overlapping the whole last line", () { + expect( + file + .span(27, 70) + .highlightMultiple("inner", {file.span(12, 70): "outer"}), + equals(""" + , +2 | /- whiz bang boom +3 | |/ zip zap zop +4 | || fwee fwoo fwip +5 | || argle bargle boo + | |'--- inner + | '---- outer + '""")); + }); + + test("overlapping part of the last line", () { + expect( + file + .span(27, 66) + .highlightMultiple("inner", {file.span(12, 70): "outer"}), + equals(""" + , +2 | /- whiz bang boom +3 | |/ zip zap zop +4 | || fwee fwoo fwip +5 | || argle bargle boo + | |'------------^ inner + | '---- outer + '""")); + }); + }); + + group("a single-line span in a multiline span", () { + test("on the first line", () { + expect( + file + .span(17, 21) + .highlightMultiple("inner", {file.span(12, 70): "outer"}), + equals(""" + , +2 | / whiz bang boom + | | ^^^^ inner +3 | | zip zap zop +4 | | fwee fwoo fwip +5 | | argle bargle boo + | '--- outer + '""")); + }); + + test("in the middle", () { + expect( + file + .span(31, 34) + .highlightMultiple("inner", {file.span(12, 70): "outer"}), + equals(""" + , +2 | / whiz bang boom +3 | | zip zap zop + | | ^^^ inner +4 | | fwee fwoo fwip +5 | | argle bargle boo + | '--- outer + '""")); + }); + + test("on the last line", () { + expect( + file + .span(60, 66) + .highlightMultiple("inner", {file.span(12, 70): "outer"}), + equals(""" + , +2 | / whiz bang boom +3 | | zip zap zop +4 | | fwee fwoo fwip +5 | | argle bargle boo + | | ^^^^^^ inner + | '--- outer + '""")); + }); + }); + + test("highlights multiple files with their URLs", () { + var file2 = SourceFile.fromString(''' +quibble bibble boop +''', url: "file2.txt"); + + expect( + file.span(31, 34).highlightMultiple("one", {file2.span(8, 14): "two"}), + equals(""" + ,--> file1.txt +3 | zip zap zop + | ^^^ one + ' + ,--> file2.txt +1 | quibble bibble boop + | ====== two + '""")); + }); +} diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart index 1ac9d35ef..f44b02fdd 100644 --- a/pkgs/source_span/test/span_test.dart +++ b/pkgs/source_span/test/span_test.dart @@ -246,7 +246,7 @@ ${colors.blue} '${colors.none}""")); 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.yellow} ^^^^^^^${colors.none} ${colors.blue} '${colors.none}""")); }); }); From 4ce9a76ad19d034d8ea5a75ad2f0f95d5c2bf4d9 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Wed, 22 Jan 2020 15:09:31 -0800 Subject: [PATCH 068/128] Re-enable lint disabled in the last PR (dart-lang/source_span#53) Some of these were lints that had been enabled while the review was ongoing, some were lints that had been around a while but ignored. Drop author field from pubspec --- pkgs/source_span/CHANGELOG.md | 2 + pkgs/source_span/analysis_options.yaml | 12 +-- pkgs/source_span/lib/src/highlighter.dart | 79 ++++++++++--------- pkgs/source_span/lib/src/span_exception.dart | 11 +-- pkgs/source_span/lib/src/utils.dart | 8 +- pkgs/source_span/pubspec.yaml | 3 +- .../test/multiple_highlight_test.dart | 74 ++++++++--------- 7 files changed, 94 insertions(+), 95 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 014cc4c63..c24535b24 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,5 @@ +# 1.6.1-dev + # 1.6.0 * Add support for highlighting multiple source spans at once, providing more diff --git a/pkgs/source_span/analysis_options.yaml b/pkgs/source_span/analysis_options.yaml index 0ce791169..ab5a4f209 100644 --- a/pkgs/source_span/analysis_options.yaml +++ b/pkgs/source_span/analysis_options.yaml @@ -2,9 +2,6 @@ include: package:pedantic/analysis_options.yaml analyzer: strong-mode: implicit-casts: false - errors: - # TODO(natebosch): fix and re-enable. - prefer_single_quotes: ignore linter: rules: - always_declare_return_types @@ -29,8 +26,7 @@ linter: - await_only_futures - camel_case_types - cancel_subscriptions - # TODO(natebosch): fix and re-enable. - #- cascade_invocations + - cascade_invocations - comment_references - constant_identifier_names - control_flow_in_finally @@ -63,12 +59,10 @@ linter: - prefer_contains - prefer_equal_for_default_values - prefer_final_fields - # TODO(natebosch): fix and re-enable. - #- prefer_final_locals + - prefer_final_locals - prefer_generic_function_type_aliases - prefer_initializing_formals - # TODO(natebosch): fix and re-enable. - #- prefer_interpolation_to_compose_strings + - prefer_interpolation_to_compose_strings - prefer_is_empty - prefer_is_not_empty - prefer_null_aware_operators diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index feb5594d5..cef6f79dd 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -114,8 +114,8 @@ class Highlighter { /// file that aren't adjacent in the original file. static bool _contiguous(List<_Line> lines) { for (var i = 0; i < lines.length - 1; i++) { - var thisLine = lines[i]; - var nextLine = lines[i + 1]; + final thisLine = lines[i]; + final nextLine = lines[i + 1]; if (thisLine.number + 1 != nextLine.number && thisLine.url == nextLine.url) { return false; @@ -127,7 +127,7 @@ class Highlighter { /// Collect all the source lines from the contexts of all spans in /// [highlights], and associates them with the highlights that cover them. static List<_Line> _collateLines(List<_Highlight> highlights) { - var highlightsByUrl = + final highlightsByUrl = groupBy(highlights, (highlight) => highlight.span.sourceUrl); for (var list in highlightsByUrl.values) { list.sort((highlight1, highlight2) => @@ -137,19 +137,19 @@ class Highlighter { return highlightsByUrl.values.expand((highlightsForFile) { // First, create a list of all the lines in the current file that we have // context for along with their line numbers. - var lines = <_Line>[]; + final lines = <_Line>[]; for (var highlight in highlightsForFile) { - var context = highlight.span.context; + final context = highlight.span.context; // If [highlight.span.context] contains lines prior to the one // [highlight.span.text] appears on, write those first. - var lineStart = findLineStart( + final lineStart = findLineStart( context, highlight.span.text, highlight.span.start.column); assert(lineStart != null); // enforced by [_normalizeContext] - var linesBeforeSpan = + final linesBeforeSpan = '\n'.allMatches(context.substring(0, lineStart)).length; - var url = highlight.span.sourceUrl; + final url = highlight.span.sourceUrl; var lineNumber = highlight.span.start.line - linesBeforeSpan; for (var line in context.split('\n')) { // Only add a line if it hasn't already been added for a previous span. @@ -161,14 +161,14 @@ class Highlighter { } // Next, associate each line with each highlights that covers it. - var activeHighlights = <_Highlight>[]; + final activeHighlights = <_Highlight>[]; var highlightIndex = 0; for (var line in lines) { activeHighlights.removeWhere((highlight) => highlight.span.sourceUrl != line.url || highlight.span.end.line < line.number); - var oldHighlightLength = activeHighlights.length; + final oldHighlightLength = activeHighlights.length; for (var highlight in highlightsForFile.skip(highlightIndex)) { if (highlight.span.start.line > line.number) break; if (highlight.span.sourceUrl != line.url) break; @@ -192,12 +192,12 @@ class Highlighter { // Each index of this list represents a column after the sidebar that could // contain a line indicating an active highlight. If it's `null`, that // column is empty; if it contains a highlight, it should be drawn for that column. - var highlightsByColumn = List<_Highlight>(_maxMultilineSpans); + final highlightsByColumn = List<_Highlight>(_maxMultilineSpans); for (var i = 0; i < _lines.length; i++) { - var line = _lines[i]; + final line = _lines[i]; if (i > 0) { - var lastLine = _lines[i - 1]; + final lastLine = _lines[i - 1]; if (lastLine.url != line.url) { _writeSidebar(end: glyph.upEnd); _buffer.writeln(); @@ -226,7 +226,7 @@ class Highlighter { _writeMultilineHighlights(line, highlightsByColumn); if (highlightsByColumn.isNotEmpty) _buffer.write(' '); - var primary = line.highlights + final primary = line.highlights .firstWhere((highlight) => highlight.isPrimary, orElse: () => null); if (primary != null) { _writeHighlightedText( @@ -263,9 +263,9 @@ class Highlighter { _writeSidebar(end: glyph.downEnd); } else { _writeSidebar(end: glyph.topLeftCorner); - _colorize(() => _buffer.write("${glyph.horizontalLine * 2}>"), + _colorize(() => _buffer.write('${glyph.horizontalLine * 2}>'), color: colors.blue); - _buffer.write(" ${p.prettyUri(url)}"); + _buffer.write(' ${p.prettyUri(url)}'); } _buffer.writeln(); } @@ -284,13 +284,13 @@ class Highlighter { var openedOnThisLine = false; String openedOnThisLineColor; - var currentColor = current == null + final currentColor = current == null ? null : current.isPrimary ? _primaryColor : _secondaryColor; var foundCurrent = false; for (var highlight in highlightsByColumn) { - var startLine = highlight?.span?.start?.line; - var endLine = highlight?.span?.end?.line; + final startLine = highlight?.span?.start?.line; + final endLine = highlight?.span?.end?.line; if (current != null && highlight == current) { foundCurrent = true; assert(startLine == line.number || endLine == line.number); @@ -312,7 +312,7 @@ class Highlighter { } } else { _colorize(() { - var vertical = openedOnThisLine ? glyph.cross : glyph.verticalLine; + final vertical = openedOnThisLine ? glyph.cross : glyph.verticalLine; if (current != null) { _buffer.write(vertical); } else if (startLine == line.number) { @@ -354,7 +354,7 @@ class Highlighter { /// This may either add or remove [highlight] from [highlightsByColumn]. void _writeIndicator( _Line line, _Highlight highlight, List<_Highlight> highlightsByColumn) { - var color = highlight.isPrimary ? _primaryColor : _secondaryColor; + final color = highlight.isPrimary ? _primaryColor : _secondaryColor; if (!isMultiline(highlight.span)) { _writeSidebar(); _buffer.write(' '); @@ -363,7 +363,7 @@ class Highlighter { _colorize(() { _writeUnderline(line, highlight.span, - highlight.isPrimary ? "^" : glyph.horizontalLineBold); + highlight.isPrimary ? '^' : glyph.horizontalLineBold); _writeLabel(highlight.label); }, color: color); _buffer.writeln(); @@ -378,7 +378,7 @@ class Highlighter { color: color); _buffer.writeln(); } else if (highlight.span.end.line == line.number) { - var coversWholeLine = highlight.span.end.column == line.text.length; + final coversWholeLine = highlight.span.end.column == line.text.length; if (coversWholeLine && highlight.label == null) { replaceWithNull(highlightsByColumn, highlight); return; @@ -413,13 +413,14 @@ class Highlighter { // Adjust the start and end columns to account for any tabs that were // converted to spaces. - var tabsBefore = _countTabs(line.text.substring(0, startColumn)); - var tabsInside = _countTabs(line.text.substring(startColumn, endColumn)); + final tabsBefore = _countTabs(line.text.substring(0, startColumn)); + final tabsInside = _countTabs(line.text.substring(startColumn, endColumn)); startColumn += tabsBefore * (_spacesPerTab - 1); endColumn += (tabsBefore + tabsInside) * (_spacesPerTab - 1); - _buffer.write(" " * startColumn); - _buffer.write(character * math.max(endColumn - startColumn, 1)); + _buffer + ..write(' ' * startColumn) + ..write(character * math.max(endColumn - startColumn, 1)); } /// Write an arrow pointing to column [column] in [line]. @@ -427,15 +428,16 @@ class Highlighter { /// If the arrow points to a tab character, this will point to the beginning /// of the tab if [beginning] is `true` and the end if it's `false`. void _writeArrow(_Line line, int column, {bool beginning = true}) { - var tabs = _countTabs(line.text.substring(0, column + (beginning ? 0 : 1))); + final tabs = + _countTabs(line.text.substring(0, column + (beginning ? 0 : 1))); _buffer ..write(glyph.horizontalLine * (1 + column + tabs * (_spacesPerTab - 1))) - ..write("^"); + ..write('^'); } /// Writes a space followed by [label] if [label] isn't `null`. void _writeLabel(String label) { - if (label != null) _buffer.write(" $label"); + if (label != null) _buffer.write(' $label'); } /// Writes a snippet from the source text, converting hard tab characters into @@ -462,8 +464,9 @@ class Highlighter { // human-friendly 1-indexed line numbers. if (line != null) text = (line + 1).toString(); _colorize(() { - _buffer.write((text ?? '').padRight(_paddingBeforeSidebar)); - _buffer.write(end ?? glyph.verticalLine); + _buffer + ..write((text ?? '').padRight(_paddingBeforeSidebar)) + ..write(end ?? glyph.verticalLine); }, color: colors.blue); } @@ -612,7 +615,7 @@ class _Highlight { text, // If the context also ends with a newline, it's possible that we don't // have the full context for that line, so we shouldn't print it at all. - span.context.endsWith("\n") + span.context.endsWith('\n') ? span.context.substring(0, span.context.length - 1) : span.context); } @@ -640,11 +643,11 @@ class _Highlight { @override String toString() { - var buffer = StringBuffer(); - if (isPrimary) buffer.write("primary "); - buffer.write("${span.start.line}:${span.start.column}-" - "${span.end.line}:${span.end.column}"); - if (label != null) buffer.write(" ($label)"); + final buffer = StringBuffer(); + if (isPrimary) buffer.write('primary '); + buffer.write('${span.start.line}:${span.start.column}-' + '${span.end.line}:${span.end.column}'); + if (label != null) buffer.write(' ($label)'); return buffer.toString(); } } diff --git a/pkgs/source_span/lib/src/span_exception.dart b/pkgs/source_span/lib/src/span_exception.dart index 5b33d06ec..32aaa4eae 100644 --- a/pkgs/source_span/lib/src/span_exception.dart +++ b/pkgs/source_span/lib/src/span_exception.dart @@ -92,11 +92,12 @@ class MultiSourceSpanException extends SourceSpanException { useColor = true; } - return "Error on " + - span.messageMultiple(message, primaryLabel, secondarySpans, - color: useColor, - primaryColor: primaryColor, - secondaryColor: secondaryColor); + final formatted = span.messageMultiple( + message, primaryLabel, secondarySpans, + color: useColor, + primaryColor: primaryColor, + secondaryColor: secondaryColor); + return 'Error on $formatted'; } } diff --git a/pkgs/source_span/lib/src/utils.dart b/pkgs/source_span/lib/src/utils.dart index 12b15b382..5cb5e90e7 100644 --- a/pkgs/source_span/lib/src/utils.dart +++ b/pkgs/source_span/lib/src/utils.dart @@ -35,16 +35,16 @@ bool isMultiline(SourceSpan span) => span.start.line != span.end.line; /// Sets the first `null` element of [list] to [element]. void replaceFirstNull(List list, E element) { - var index = list.indexOf(null); - if (index < 0) throw ArgumentError("$list contains no null elements."); + final index = list.indexOf(null); + if (index < 0) throw ArgumentError('$list contains no null elements.'); list[index] = element; } /// Sets the element of [list] that currently contains [element] to `null`. void replaceWithNull(List list, E element) { - var index = list.indexOf(element); + final index = list.indexOf(element); if (index < 0) { - throw ArgumentError("$list contains no elements matching $element."); + throw ArgumentError('$list contains no elements matching $element.'); } list[index] = null; diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 2054423d5..fce212461 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,8 +1,7 @@ name: source_span -version: 1.6.0 +version: 1.6.1-dev description: A library for identifying source spans and locations. -author: Dart Team homepage: https://github.com/dart-lang/source_span environment: diff --git a/pkgs/source_span/test/multiple_highlight_test.dart b/pkgs/source_span/test/multiple_highlight_test.dart index f0cceedef..d9d1b30c8 100644 --- a/pkgs/source_span/test/multiple_highlight_test.dart +++ b/pkgs/source_span/test/multiple_highlight_test.dart @@ -26,13 +26,13 @@ zip zap zop fwee fwoo fwip argle bargle boo gibble bibble bop -''', url: "file1.txt"); +''', url: 'file1.txt'); }); - test("highlights spans on separate lines", () { + test('highlights spans on separate lines', () { expect( file.span(17, 21).highlightMultiple( - "one", {file.span(31, 34): "two", file.span(4, 7): "three"}), + 'one', {file.span(31, 34): 'two', file.span(4, 7): 'three'}), equals(""" , 1 | foo bar baz @@ -44,10 +44,10 @@ gibble bibble bop '""")); }); - test("highlights spans on the same line", () { + test('highlights spans on the same line', () { expect( file.span(17, 21).highlightMultiple( - "one", {file.span(22, 26): "two", file.span(12, 16): "three"}), + 'one', {file.span(22, 26): 'two', file.span(12, 16): 'three'}), equals(""" , 2 | whiz bang boom @@ -57,10 +57,10 @@ gibble bibble bop '""")); }); - test("highlights overlapping spans on the same line", () { + test('highlights overlapping spans on the same line', () { expect( file.span(17, 21).highlightMultiple( - "one", {file.span(20, 26): "two", file.span(12, 18): "three"}), + 'one', {file.span(20, 26): 'two', file.span(12, 18): 'three'}), equals(""" , 2 | whiz bang boom @@ -70,10 +70,10 @@ gibble bibble bop '""")); }); - test("highlights multiple multiline spans", () { + test('highlights multiple multiline spans', () { expect( file.span(27, 54).highlightMultiple( - "one", {file.span(54, 89): "two", file.span(0, 27): "three"}), + 'one', {file.span(54, 89): 'two', file.span(0, 27): 'three'}), equals(""" , 1 | / foo bar baz @@ -88,10 +88,10 @@ gibble bibble bop '""")); }); - test("highlights multiple overlapping multiline spans", () { + test('highlights multiple overlapping multiline spans', () { expect( file.span(12, 70).highlightMultiple( - "one", {file.span(54, 89): "two", file.span(0, 27): "three"}), + 'one', {file.span(54, 89): 'two', file.span(0, 27): 'three'}), equals(""" , 1 | /- foo bar baz @@ -106,12 +106,12 @@ gibble bibble bop '""")); }); - test("highlights many layers of overlaps", () { + test('highlights many layers of overlaps', () { expect( - file.span(0, 54).highlightMultiple("one", { - file.span(12, 77): "two", - file.span(27, 84): "three", - file.span(39, 88): "four" + file.span(0, 54).highlightMultiple('one', { + file.span(12, 77): 'two', + file.span(27, 84): 'three', + file.span(39, 88): 'four' }), equals(""" , @@ -129,11 +129,11 @@ gibble bibble bop }); group("highlights a multiline span that's a subset", () { - test("with no first or last line overlap", () { + test('with no first or last line overlap', () { expect( file .span(27, 53) - .highlightMultiple("inner", {file.span(12, 70): "outer"}), + .highlightMultiple('inner', {file.span(12, 70): 'outer'}), equals(""" , 2 | /- whiz bang boom @@ -145,11 +145,11 @@ gibble bibble bop '""")); }); - test("overlapping the whole first line", () { + test('overlapping the whole first line', () { expect( file .span(12, 53) - .highlightMultiple("inner", {file.span(12, 70): "outer"}), + .highlightMultiple('inner', {file.span(12, 70): 'outer'}), equals(""" , 2 | // whiz bang boom @@ -161,11 +161,11 @@ gibble bibble bop '""")); }); - test("overlapping part of first line", () { + test('overlapping part of first line', () { expect( file .span(17, 53) - .highlightMultiple("inner", {file.span(12, 70): "outer"}), + .highlightMultiple('inner', {file.span(12, 70): 'outer'}), equals(""" , 2 | /- whiz bang boom @@ -178,11 +178,11 @@ gibble bibble bop '""")); }); - test("overlapping the whole last line", () { + test('overlapping the whole last line', () { expect( file .span(27, 70) - .highlightMultiple("inner", {file.span(12, 70): "outer"}), + .highlightMultiple('inner', {file.span(12, 70): 'outer'}), equals(""" , 2 | /- whiz bang boom @@ -194,11 +194,11 @@ gibble bibble bop '""")); }); - test("overlapping part of the last line", () { + test('overlapping part of the last line', () { expect( file .span(27, 66) - .highlightMultiple("inner", {file.span(12, 70): "outer"}), + .highlightMultiple('inner', {file.span(12, 70): 'outer'}), equals(""" , 2 | /- whiz bang boom @@ -211,12 +211,12 @@ gibble bibble bop }); }); - group("a single-line span in a multiline span", () { - test("on the first line", () { + group('a single-line span in a multiline span', () { + test('on the first line', () { expect( file .span(17, 21) - .highlightMultiple("inner", {file.span(12, 70): "outer"}), + .highlightMultiple('inner', {file.span(12, 70): 'outer'}), equals(""" , 2 | / whiz bang boom @@ -228,11 +228,11 @@ gibble bibble bop '""")); }); - test("in the middle", () { + test('in the middle', () { expect( file .span(31, 34) - .highlightMultiple("inner", {file.span(12, 70): "outer"}), + .highlightMultiple('inner', {file.span(12, 70): 'outer'}), equals(""" , 2 | / whiz bang boom @@ -244,11 +244,11 @@ gibble bibble bop '""")); }); - test("on the last line", () { + test('on the last line', () { expect( file .span(60, 66) - .highlightMultiple("inner", {file.span(12, 70): "outer"}), + .highlightMultiple('inner', {file.span(12, 70): 'outer'}), equals(""" , 2 | / whiz bang boom @@ -261,13 +261,13 @@ gibble bibble bop }); }); - test("highlights multiple files with their URLs", () { - var file2 = SourceFile.fromString(''' + test('highlights multiple files with their URLs', () { + final file2 = SourceFile.fromString(''' quibble bibble boop -''', url: "file2.txt"); +''', url: 'file2.txt'); expect( - file.span(31, 34).highlightMultiple("one", {file2.span(8, 14): "two"}), + file.span(31, 34).highlightMultiple('one', {file2.span(8, 14): 'two'}), equals(""" ,--> file1.txt 3 | zip zap zop From 97668dae7172ca2b12f8161141aac6906962854b Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 17 Mar 2020 19:41:58 -0700 Subject: [PATCH 069/128] Add SourceSpan.subspan() (dart-lang/source_span#54) This is useful when a span may cover multiple logical tokens, and a user wants to single out a single specific token. --- pkgs/source_span/CHANGELOG.md | 5 +- pkgs/source_span/lib/src/file.dart | 21 +++++ pkgs/source_span/lib/src/span.dart | 52 ++++++++++++ pkgs/source_span/pubspec.yaml | 2 +- pkgs/source_span/test/file_test.dart | 121 +++++++++++++++++++++++++++ pkgs/source_span/test/span_test.dart | 120 ++++++++++++++++++++++++++ 6 files changed, 319 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index c24535b24..5da330e47 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,4 +1,7 @@ -# 1.6.1-dev +# 1.7.0 + +* Add a `SourceSpan.subspan()` extension method which returns a slice of an + existing source span. # 1.6.0 diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index a03a875a5..9ad595cdf 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -423,4 +423,25 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { return _FileSpan(file, start, end); } } + + /// See `SourceSpanExtension.subspan`. + FileSpan subspan(int start, [int end]) { + RangeError.checkValidRange(start, end, length); + if (start == 0 && (end == null || end == length)) return this; + return file.span(_start + start, end == null ? _end : _start + end); + } +} + +// TODO(#52): Move these to instance methods in the next breaking release. +/// Extension methods on the [FileSpan] API. +extension FileSpanExtension on FileSpan { + /// See `SourceSpanExtension.subspan`. + FileSpan subspan(int start, [int end]) { + RangeError.checkValidRange(start, end, length); + if (start == 0 && (end == null || end == length)) return this; + + final startOffset = this.start.offset; + return file.span( + startOffset + start, end == null ? this.end.offset : startOffset + end); + } } diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index 51e81ab80..15f0d34c1 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -2,6 +2,7 @@ // 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:charcode/charcode.dart'; import 'package:path/path.dart' as p; import 'package:term_glyph/term_glyph.dart' as glyph; @@ -179,4 +180,55 @@ extension SourceSpanExtension on SourceSpan { primaryColor: primaryColor, secondaryColor: secondaryColor) .highlight(); + + /// Returns a span from [start] code units (inclusive) to [end] code units + /// (exclusive) after the beginning of this span. + SourceSpan subspan(int start, [int end]) { + RangeError.checkValidRange(start, end, length); + if (start == 0 && (end == null || end == length)) return this; + + final text = this.text; + final startLocation = this.start; + var line = startLocation.line; + var column = startLocation.column; + + // Adjust [line] and [column] as necessary if the character at [i] in [text] + // is a newline. + void consumeCodePoint(int i) { + final codeUnit = text.codeUnitAt(i); + if (codeUnit == $lf || + // A carriage return counts as a newline, but only if it's not + // followed by a line feed. + (codeUnit == $cr && + (i + 1 == text.length || text.codeUnitAt(i + 1) != $lf))) { + line += 1; + column = 0; + } else { + column += 1; + } + } + + for (var i = 0; i < start; i++) { + consumeCodePoint(i); + } + + final newStartLocation = SourceLocation(startLocation.offset + start, + sourceUrl: sourceUrl, line: line, column: column); + + SourceLocation newEndLocation; + if (end == null || end == length) { + newEndLocation = this.end; + } else if (end == start) { + newEndLocation = newStartLocation; + } else if (end != null && end != length) { + for (var i = start; i < end; i++) { + consumeCodePoint(i); + } + newEndLocation = SourceLocation(startLocation.offset + end, + sourceUrl: sourceUrl, line: line, column: column); + } + + return SourceSpan( + newStartLocation, newEndLocation, text.substring(start, end)); + } } diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index fce212461..126d9c09f 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.6.1-dev +version: 1.7.0 description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index 91922006d..63b523f3b 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/test/file_test.dart @@ -405,5 +405,126 @@ zip zap zop expect(span.expand(other), equals(other)); }); }); + + group('subspan()', () { + FileSpan span; + setUp(() { + span = file.span(5, 11); // "ar baz" + }); + + group('errors', () { + test('start must be greater than zero', () { + expect(() => span.subspan(-1), throwsRangeError); + }); + + test('start must be less than or equal to length', () { + expect(() => span.subspan(span.length + 1), throwsRangeError); + }); + + test('end must be greater than start', () { + expect(() => span.subspan(2, 1), throwsRangeError); + }); + + test('end must be less than or equal to length', () { + expect(() => span.subspan(0, span.length + 1), throwsRangeError); + }); + }); + + test('preserves the source URL', () { + final result = span.subspan(1, 2); + expect(result.start.sourceUrl, equals(span.sourceUrl)); + expect(result.end.sourceUrl, equals(span.sourceUrl)); + }); + + group('returns the original span', () { + test('with an implicit end', + () => expect(span.subspan(0), equals(span))); + + test('with an explicit end', + () => expect(span.subspan(0, span.length), equals(span))); + }); + + group('within a single line', () { + test('returns a strict substring of the original span', () { + final result = span.subspan(1, 5); + expect(result.text, equals('r ba')); + expect(result.start.offset, equals(6)); + expect(result.start.line, equals(0)); + expect(result.start.column, equals(6)); + expect(result.end.offset, equals(10)); + expect(result.end.line, equals(0)); + expect(result.end.column, equals(10)); + }); + + test('an implicit end goes to the end of the original span', () { + final result = span.subspan(1); + expect(result.text, equals('r baz')); + expect(result.start.offset, equals(6)); + expect(result.start.line, equals(0)); + expect(result.start.column, equals(6)); + expect(result.end.offset, equals(11)); + expect(result.end.line, equals(0)); + expect(result.end.column, equals(11)); + }); + + test('can return an empty span', () { + final result = span.subspan(3, 3); + expect(result.text, isEmpty); + expect(result.start.offset, equals(8)); + expect(result.start.line, equals(0)); + expect(result.start.column, equals(8)); + expect(result.end, equals(result.start)); + }); + }); + + group('across multiple lines', () { + setUp(() { + span = file.span(22, 30); // "boom\nzip" + }); + + test('with start and end in the middle of a line', () { + final result = span.subspan(3, 6); + expect(result.text, equals('m\nz')); + expect(result.start.offset, equals(25)); + expect(result.start.line, equals(1)); + expect(result.start.column, equals(13)); + expect(result.end.offset, equals(28)); + expect(result.end.line, equals(2)); + expect(result.end.column, equals(1)); + }); + + test('with start at the end of a line', () { + final result = span.subspan(4, 6); + expect(result.text, equals('\nz')); + expect(result.start.offset, equals(26)); + expect(result.start.line, equals(1)); + expect(result.start.column, equals(14)); + }); + + test('with start at the beginning of a line', () { + final result = span.subspan(5, 6); + expect(result.text, equals('z')); + expect(result.start.offset, equals(27)); + expect(result.start.line, equals(2)); + expect(result.start.column, equals(0)); + }); + + test('with end at the end of a line', () { + final result = span.subspan(3, 4); + expect(result.text, equals('m')); + expect(result.end.offset, equals(26)); + expect(result.end.line, equals(1)); + expect(result.end.column, equals(14)); + }); + + test('with end at the beginning of a line', () { + final result = span.subspan(3, 5); + expect(result.text, equals('m\n')); + expect(result.end.offset, equals(27)); + expect(result.end.line, equals(2)); + expect(result.end.column, equals(0)); + }); + }); + }); }); } diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart index f44b02fdd..838d6b7cf 100644 --- a/pkgs/source_span/test/span_test.dart +++ b/pkgs/source_span/test/span_test.dart @@ -181,6 +181,126 @@ void main() { }); }); + group('subspan()', () { + group('errors', () { + test('start must be greater than zero', () { + expect(() => span.subspan(-1), throwsRangeError); + }); + + test('start must be less than or equal to length', () { + expect(() => span.subspan(span.length + 1), throwsRangeError); + }); + + test('end must be greater than start', () { + expect(() => span.subspan(2, 1), throwsRangeError); + }); + + test('end must be less than or equal to length', () { + expect(() => span.subspan(0, span.length + 1), throwsRangeError); + }); + }); + + test('preserves the source URL', () { + final result = span.subspan(1, 2); + expect(result.start.sourceUrl, equals(span.sourceUrl)); + expect(result.end.sourceUrl, equals(span.sourceUrl)); + }); + + group('returns the original span', () { + test('with an implicit end', () => expect(span.subspan(0), equals(span))); + + test('with an explicit end', + () => expect(span.subspan(0, span.length), equals(span))); + }); + + group('within a single line', () { + test('returns a strict substring of the original span', () { + final result = span.subspan(1, 5); + expect(result.text, equals('oo b')); + expect(result.start.offset, equals(6)); + expect(result.start.line, equals(0)); + expect(result.start.column, equals(6)); + expect(result.end.offset, equals(10)); + expect(result.end.line, equals(0)); + expect(result.end.column, equals(10)); + }); + + test('an implicit end goes to the end of the original span', () { + final result = span.subspan(1); + expect(result.text, equals('oo bar')); + expect(result.start.offset, equals(6)); + expect(result.start.line, equals(0)); + expect(result.start.column, equals(6)); + expect(result.end.offset, equals(12)); + expect(result.end.line, equals(0)); + expect(result.end.column, equals(12)); + }); + + test('can return an empty span', () { + final result = span.subspan(3, 3); + expect(result.text, isEmpty); + expect(result.start.offset, equals(8)); + expect(result.start.line, equals(0)); + expect(result.start.column, equals(8)); + expect(result.end, equals(result.start)); + }); + }); + + group('across multiple lines', () { + setUp(() { + span = SourceSpan( + SourceLocation(5, line: 2, column: 0), + SourceLocation(16, line: 4, column: 3), + 'foo\n' + 'bar\n' + 'baz'); + }); + + test('with start and end in the middle of a line', () { + final result = span.subspan(2, 5); + expect(result.text, equals('o\nb')); + expect(result.start.offset, equals(7)); + expect(result.start.line, equals(2)); + expect(result.start.column, equals(2)); + expect(result.end.offset, equals(10)); + expect(result.end.line, equals(3)); + expect(result.end.column, equals(1)); + }); + + test('with start at the end of a line', () { + final result = span.subspan(3, 5); + expect(result.text, equals('\nb')); + expect(result.start.offset, equals(8)); + expect(result.start.line, equals(2)); + expect(result.start.column, equals(3)); + }); + + test('with start at the beginning of a line', () { + final result = span.subspan(4, 5); + expect(result.text, equals('b')); + expect(result.start.offset, equals(9)); + expect(result.start.line, equals(3)); + expect(result.start.column, equals(0)); + }); + + test('with end at the end of a line', () { + final result = span.subspan(2, 3); + expect(result.text, equals('o')); + expect(result.end.offset, equals(8)); + expect(result.end.line, equals(2)); + expect(result.end.column, equals(3)); + }); + + test('with end at the beginning of a line', () { + final result = span.subspan(2, 4); + expect(result.text, equals('o\n')); + expect(result.end.offset, equals(9)); + expect(result.end.line, equals(3)); + expect(result.end.column, equals(0)); + }); + }); + }); + group('message()', () { test('prints the text being described', () { expect(span.message('oh no'), equals(""" From 4ddf2b607bafa96ce6285ed2d579b78cb26a12fe Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Tue, 14 Jul 2020 15:47:02 -0700 Subject: [PATCH 070/128] Merge the null_safety branch into master (dart-lang/source_span#56) --- pkgs/source_span/.travis.yml | 40 ++++++--- pkgs/source_span/CHANGELOG.md | 6 ++ pkgs/source_span/analysis_options.yaml | 2 + pkgs/source_span/lib/src/file.dart | 48 +++++----- pkgs/source_span/lib/src/highlighter.dart | 60 +++++++------ pkgs/source_span/lib/src/location.dart | 10 +-- pkgs/source_span/lib/src/location_mixin.dart | 2 +- pkgs/source_span/lib/src/span.dart | 10 +-- pkgs/source_span/lib/src/span_exception.dart | 22 ++--- pkgs/source_span/lib/src/span_mixin.dart | 2 +- pkgs/source_span/lib/src/utils.dart | 10 +-- pkgs/source_span/pubspec.yaml | 88 +++++++++++++++++-- pkgs/source_span/test/file_test.dart | 8 +- pkgs/source_span/test/highlight_test.dart | 4 +- pkgs/source_span/test/location_test.dart | 2 +- .../test/multiple_highlight_test.dart | 4 +- pkgs/source_span/test/span_test.dart | 5 +- pkgs/source_span/test/utils_test.dart | 8 +- 18 files changed, 214 insertions(+), 117 deletions(-) diff --git a/pkgs/source_span/.travis.yml b/pkgs/source_span/.travis.yml index 9738ed50e..8361c623e 100644 --- a/pkgs/source_span/.travis.yml +++ b/pkgs/source_span/.travis.yml @@ -1,24 +1,38 @@ language: dart dart: - - dev - - 2.6.0 +- dev -dart_task: - - test: --platform vm,chrome - -matrix: +jobs: include: - # Only validate formatting using the dev release - - dart: dev - dart_task: dartfmt - - dart: dev - dart_task: - dartanalyzer: --fatal-warnings --fatal-infos . + - stage: analyze_and_format + name: "Analyze test/" + dart: dev + os: linux + script: dartanalyzer --enable-experiment=non-nullable --fatal-warnings --fatal-infos . + - stage: analyze_and_format + name: "Format" + dart: dev + os: linux + script: dartfmt -n --set-exit-if-changed . + - stage: test + name: "Vm Tests" + dart: dev + os: linux + script: pub run --enable-experiment=non-nullable test -p vm + - stage: test + name: "Web Tests" + dart: dev + os: linux + script: pub run --enable-experiment=non-nullable test -p chrome + +stages: + - analyze_and_format + - test # Only building master means that we don't run two builds for each pull request. branches: - only: [master] + only: [master, null_safety] cache: directories: diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 5da330e47..1723b0fc2 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,9 @@ +# 1.8.0-nullsafety + +* Migrate to null safety. + * Apis have been migrated to reflect the existing assumptions in the code + and are not expected to be breaking. + # 1.7.0 * Add a `SourceSpan.subspan()` extension method which returns a slice of an diff --git a/pkgs/source_span/analysis_options.yaml b/pkgs/source_span/analysis_options.yaml index ab5a4f209..ced2e21b2 100644 --- a/pkgs/source_span/analysis_options.yaml +++ b/pkgs/source_span/analysis_options.yaml @@ -2,6 +2,8 @@ include: package:pedantic/analysis_options.yaml analyzer: strong-mode: implicit-casts: false + enable-experiment: + - non-nullable linter: rules: - always_declare_return_types diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 9ad595cdf..6fbcd4193 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -23,7 +23,7 @@ class SourceFile { /// The URL where the source file is located. /// /// This may be null, indicating that the URL is unknown or unavailable. - final Uri url; + final Uri? url; /// An array of offsets for each line beginning in the file. /// @@ -47,7 +47,7 @@ class SourceFile { /// increasing offsets. In that case, we can find the line for an offset /// quickly by first checking to see if the offset is on the same line as the /// previous result. - int _cachedLine; + int? _cachedLine; /// This constructor is deprecated. /// @@ -71,7 +71,7 @@ class SourceFile { /// forwards-compatibility, callers should only pass in characters less than /// or equal to `0xFFFF`. SourceFile.decoded(Iterable decodedChars, {url}) - : url = url is String ? Uri.parse(url) : url as Uri, + : 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]; @@ -87,7 +87,7 @@ class SourceFile { /// 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]) { + FileSpan span(int start, [int? end]) { end ??= length; return _FileSpan(this, start, end); } @@ -107,10 +107,10 @@ class SourceFile { if (offset < _lineStarts.first) return -1; if (offset >= _lineStarts.last) return _lineStarts.length - 1; - if (_isNearCachedLine(offset)) return _cachedLine; + if (_isNearCachedLine(offset)) return _cachedLine!; _cachedLine = _binarySearch(offset) - 1; - return _cachedLine; + return _cachedLine!; } /// Returns `true` if [offset] is near [_cachedLine]. @@ -119,20 +119,21 @@ class SourceFile { /// updates [_cachedLine] to point to that. bool _isNearCachedLine(int offset) { if (_cachedLine == null) return false; + final cachedLine = _cachedLine!; // See if it's before the cached line. - if (offset < _lineStarts[_cachedLine]) return false; + if (offset < _lineStarts[cachedLine]) return false; // See if it's on the cached line. - if (_cachedLine >= _lineStarts.length - 1 || - offset < _lineStarts[_cachedLine + 1]) { + if (cachedLine >= _lineStarts.length - 1 || + offset < _lineStarts[cachedLine + 1]) { return true; } // See if it's on the next line. - if (_cachedLine >= _lineStarts.length - 2 || - offset < _lineStarts[_cachedLine + 2]) { - _cachedLine++; + if (cachedLine >= _lineStarts.length - 2 || + offset < _lineStarts[cachedLine + 2]) { + _cachedLine = cachedLine + 1; return true; } @@ -161,7 +162,7 @@ class SourceFile { /// /// If [line] is passed, it's assumed to be the line containing [offset] and /// is used to more efficiently compute the column. - int getColumn(int offset, {int line}) { + int getColumn(int offset, {int? line}) { if (offset < 0) { throw RangeError('Offset may not be negative, was $offset.'); } else if (offset > length) { @@ -189,7 +190,7 @@ class SourceFile { /// Gets the offset for a [line] and [column]. /// /// [column] defaults to 0. - int getOffset(int line, [int column]) { + int getOffset(int line, [int? column]) { column ??= 0; if (line < 0) { @@ -213,7 +214,7 @@ class SourceFile { /// Returns the text of the file from [start] to [end] (exclusive). /// /// If [end] isn't passed, it defaults to the end of the file. - String getText(int start, [int end]) => + String getText(int start, [int? end]) => String.fromCharCodes(_decodedChars.sublist(start, end)); } @@ -231,7 +232,7 @@ class FileLocation extends SourceLocationMixin implements SourceLocation { final int offset; @override - Uri get sourceUrl => file.url; + Uri? get sourceUrl => file.url; @override int get line => file.getLine(offset); @@ -299,7 +300,7 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { final int _end; @override - Uri get sourceUrl => file.url; + Uri? get sourceUrl => file.url; @override int get length => _end - _start; @@ -318,7 +319,7 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { final endLine = file.getLine(_end); final endColumn = file.getColumn(_end); - int endOffset; + int? endOffset; if (endColumn == 0 && endLine != 0) { // If [end] is at the very beginning of the line, the span covers the // previous newline, so we only want to include the previous line in the @@ -362,16 +363,15 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { int compareTo(SourceSpan other) { if (other is! _FileSpan) return super.compareTo(other); - final otherFile = other as _FileSpan; - final result = _start.compareTo(otherFile._start); - return result == 0 ? _end.compareTo(otherFile._end) : result; + final result = _start.compareTo(other._start); + return result == 0 ? _end.compareTo(other._end) : result; } @override SourceSpan union(SourceSpan other) { if (other is! FileSpan) return super.union(other); - final span = expand(other as _FileSpan); + final span = expand(other); if (other is _FileSpan) { if (_start > other._end || other._start > _end) { @@ -425,7 +425,7 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { } /// See `SourceSpanExtension.subspan`. - FileSpan subspan(int start, [int end]) { + FileSpan subspan(int start, [int? end]) { RangeError.checkValidRange(start, end, length); if (start == 0 && (end == null || end == length)) return this; return file.span(_start + start, end == null ? _end : _start + end); @@ -436,7 +436,7 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { /// Extension methods on the [FileSpan] API. extension FileSpanExtension on FileSpan { /// See `SourceSpanExtension.subspan`. - FileSpan subspan(int start, [int end]) { + FileSpan subspan(int start, [int? end]) { RangeError.checkValidRange(start, end, length); if (start == 0 && (end == null || end == length)) return this; diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index cef6f79dd..491dae5ba 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -6,7 +6,6 @@ import 'dart:math' as math; import 'package:charcode/charcode.dart'; import 'package:collection/collection.dart'; -import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; import 'package:term_glyph/term_glyph.dart' as glyph; @@ -23,11 +22,11 @@ class Highlighter { /// The color to highlight the primary [_Highlight] within its context, or /// `null` if it should not be colored. - final String _primaryColor; + final String? _primaryColor; /// The color to highlight the secondary [_Highlight]s within their context, /// or `null` if they should not be colored. - final String _secondaryColor; + final String? _secondaryColor; /// The number of characters before the bar in the sidebar. final int _paddingBeforeSidebar; @@ -63,7 +62,7 @@ class Highlighter { : this._(_collateLines([_Highlight(span, primary: true)]), () { if (color == true) return colors.red; if (color == false) return null; - return color as String; + return color as String?; }(), null); /// Creates a [Highlighter] that will return a string highlighting @@ -83,7 +82,7 @@ class Highlighter { /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors Highlighter.multiple(SourceSpan primarySpan, String primaryLabel, Map secondarySpans, - {bool color = false, String primaryColor, String secondaryColor}) + {bool color = false, String? primaryColor, String? secondaryColor}) : this._( _collateLines([ _Highlight(primarySpan, label: primaryLabel, primary: true), @@ -108,7 +107,8 @@ class Highlighter { .where((highlight) => isMultiline(highlight.span)) .length) .reduce(math.max), - _multipleFiles = !isAllTheSame(_lines.map((line) => line.url)); + _multipleFiles = + !isAllTheSame(_lines.map((line) => line.url).whereType()); /// Returns whether [lines] contains any adjacent lines from the same source /// file that aren't adjacent in the original file. @@ -127,8 +127,8 @@ class Highlighter { /// Collect all the source lines from the contexts of all spans in /// [highlights], and associates them with the highlights that cover them. static List<_Line> _collateLines(List<_Highlight> highlights) { - final highlightsByUrl = - groupBy(highlights, (highlight) => highlight.span.sourceUrl); + final highlightsByUrl = groupBy<_Highlight, Uri?>( + highlights, (highlight) => highlight.span.sourceUrl); for (var list in highlightsByUrl.values) { list.sort((highlight1, highlight2) => highlight1.span.compareTo(highlight2.span)); @@ -143,8 +143,7 @@ class Highlighter { // If [highlight.span.context] contains lines prior to the one // [highlight.span.text] appears on, write those first. final lineStart = findLineStart( - context, highlight.span.text, highlight.span.start.column); - assert(lineStart != null); // enforced by [_normalizeContext] + context, highlight.span.text, highlight.span.start.column)!; final linesBeforeSpan = '\n'.allMatches(context.substring(0, lineStart)).length; @@ -192,7 +191,8 @@ class Highlighter { // Each index of this list represents a column after the sidebar that could // contain a line indicating an active highlight. If it's `null`, that // column is empty; if it contains a highlight, it should be drawn for that column. - final highlightsByColumn = List<_Highlight>(_maxMultilineSpans); + final highlightsByColumn = + List<_Highlight?>.filled(_maxMultilineSpans, null); for (var i = 0; i < _lines.length; i++) { final line = _lines[i]; @@ -226,8 +226,10 @@ class Highlighter { _writeMultilineHighlights(line, highlightsByColumn); if (highlightsByColumn.isNotEmpty) _buffer.write(' '); - final primary = line.highlights - .firstWhere((highlight) => highlight.isPrimary, orElse: () => null); + final primaryIdx = + line.highlights.indexWhere((highlight) => highlight.isPrimary); + final primary = primaryIdx == -1 ? null : line.highlights[primaryIdx]; + if (primary != null) { _writeHighlightedText( line.text, @@ -258,7 +260,7 @@ class Highlighter { /// Writes the beginning of the file highlight for the file with the given /// [url]. - void _writeFileStart(Uri url) { + void _writeFileStart(Uri? url) { if (!_multipleFiles || url == null) { _writeSidebar(end: glyph.downEnd); } else { @@ -277,20 +279,20 @@ class Highlighter { /// written. If it appears in [highlightsByColumn], a horizontal line is /// written from its column to the rightmost column. void _writeMultilineHighlights( - _Line line, List<_Highlight> highlightsByColumn, - {_Highlight current}) { + _Line line, List<_Highlight?> highlightsByColumn, + {_Highlight? current}) { // Whether we've written a sidebar indicator for opening a new span on this // line, and which color should be used for that indicator's rightward line. var openedOnThisLine = false; - String openedOnThisLineColor; + String? openedOnThisLineColor; final currentColor = current == null ? null : current.isPrimary ? _primaryColor : _secondaryColor; var foundCurrent = false; for (var highlight in highlightsByColumn) { - final startLine = highlight?.span?.start?.line; - final endLine = highlight?.span?.end?.line; + final startLine = highlight?.span.start.line; + final endLine = highlight?.span.end.line; if (current != null && highlight == current) { foundCurrent = true; assert(startLine == line.number || endLine == line.number); @@ -322,9 +324,9 @@ class Highlighter { }, color: openedOnThisLineColor); openedOnThisLine = true; openedOnThisLineColor ??= - highlight.isPrimary ? _primaryColor : _secondaryColor; + highlight!.isPrimary ? _primaryColor : _secondaryColor; } else if (endLine == line.number && - highlight.span.end.column == line.text.length) { + highlight!.span.end.column == line.text.length) { _buffer.write(highlight.label == null ? glyph.glyphOrAscii('└', '\\') : vertical); @@ -341,7 +343,7 @@ class Highlighter { // Writes [text], with text between [startColumn] and [endColumn] colorized in // the same way as [_colorize]. void _writeHighlightedText(String text, int startColumn, int endColumn, - {@required String color}) { + {required String? color}) { _writeText(text.substring(0, startColumn)); _colorize(() => _writeText(text.substring(startColumn, endColumn)), color: color); @@ -353,7 +355,7 @@ class Highlighter { /// /// This may either add or remove [highlight] from [highlightsByColumn]. void _writeIndicator( - _Line line, _Highlight highlight, List<_Highlight> highlightsByColumn) { + _Line line, _Highlight highlight, List<_Highlight?> highlightsByColumn) { final color = highlight.isPrimary ? _primaryColor : _secondaryColor; if (!isMultiline(highlight.span)) { _writeSidebar(); @@ -436,7 +438,7 @@ class Highlighter { } /// Writes a space followed by [label] if [label] isn't `null`. - void _writeLabel(String label) { + void _writeLabel(String? label) { if (label != null) _buffer.write(' $label'); } @@ -457,7 +459,7 @@ class Highlighter { // // If [text] is given, it's used in place of the line number. It can't be // passed at the same time as [line]. - void _writeSidebar({int line, String text, String end}) { + void _writeSidebar({int? line, String? text, String? end}) { assert(line == null || text == null); // Add 1 to line to convert from computer-friendly 0-indexed line numbers to @@ -489,7 +491,7 @@ class Highlighter { /// Colors all text written to [_buffer] during [callback], if colorization is /// enabled and [color] is not `null`. - void _colorize(void Function() callback, {@required String color}) { + void _colorize(void Function() callback, {required String? color}) { if (_primaryColor != null && color != null) _buffer.write(color); callback(); if (_primaryColor != null && color != null) _buffer.write(colors.none); @@ -513,7 +515,7 @@ class _Highlight { /// /// This helps distinguish clarify what each highlight means when multiple are /// used in the same message. - final String label; + final String? label; _Highlight(SourceSpan span, {this.label, bool primary = false}) : span = (() { @@ -636,7 +638,7 @@ class _Highlight { /// Returns whether [span]'s text runs all the way to the end of its context. static bool _isTextAtEndOfContext(SourceSpanWithContext span) => - findLineStart(span.context, span.text, span.start.column) + + findLineStart(span.context, span.text, span.start.column)! + span.start.column + span.length == span.context.length; @@ -661,7 +663,7 @@ class _Line { final int number; /// The URL of the source file in which this line appears. - final Uri url; + final Uri? url; /// All highlights that cover any portion of this line, in source span order. /// diff --git a/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart index 93942f05f..097961841 100644 --- a/pkgs/source_span/lib/src/location.dart +++ b/pkgs/source_span/lib/src/location.dart @@ -16,7 +16,7 @@ class SourceLocation implements Comparable { /// /// This may be null, indicating that the source URL is unknown or /// unavailable. - final Uri sourceUrl; + final Uri? sourceUrl; /// The 0-based offset of this location in the source. final int offset; @@ -42,9 +42,9 @@ class SourceLocation implements Comparable { /// means that [line] defaults to 0 and [column] defaults to [offset]. /// /// [sourceUrl] may be either a [String], a [Uri], or `null`. - SourceLocation(this.offset, {sourceUrl, int line, int column}) + SourceLocation(this.offset, {sourceUrl, int? line, int? column}) : sourceUrl = - sourceUrl is String ? Uri.parse(sourceUrl) : sourceUrl as Uri, + sourceUrl is String ? Uri.parse(sourceUrl) : sourceUrl as Uri?, line = line ?? 0, column = column ?? offset { if (offset < 0) { @@ -89,7 +89,7 @@ class SourceLocation implements Comparable { offset == other.offset; @override - int get hashCode => sourceUrl.hashCode + offset; + int get hashCode => (sourceUrl?.hashCode ?? 0) + offset; @override String toString() => '<$runtimeType: $offset $toolString>'; @@ -98,6 +98,6 @@ class SourceLocation implements Comparable { /// A base class for source locations with [offset], [line], and [column] known /// at construction time. class SourceLocationBase extends SourceLocation { - SourceLocationBase(int offset, {sourceUrl, int line, int column}) + SourceLocationBase(int offset, {sourceUrl, int? line, int? column}) : super(offset, sourceUrl: sourceUrl, line: line, column: column); } diff --git a/pkgs/source_span/lib/src/location_mixin.dart b/pkgs/source_span/lib/src/location_mixin.dart index a54e363d0..9a1f930f8 100644 --- a/pkgs/source_span/lib/src/location_mixin.dart +++ b/pkgs/source_span/lib/src/location_mixin.dart @@ -48,7 +48,7 @@ abstract class SourceLocationMixin implements SourceLocation { offset == other.offset; @override - int get hashCode => sourceUrl.hashCode + offset; + int get hashCode => (sourceUrl?.hashCode ?? 0) + offset; @override String toString() => '<$runtimeType: $offset $toolString>'; diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index 15f0d34c1..94c05ba7a 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -27,7 +27,7 @@ abstract class SourceSpan implements Comparable { /// /// This may be null, indicating that the source URL is unknown or /// unavailable. - Uri get sourceUrl; + Uri? get sourceUrl; /// The length of this span, in characters. int get length; @@ -139,7 +139,7 @@ extension SourceSpanExtension on SourceSpan { /// [FileSpan]s). String messageMultiple( String message, String label, Map secondarySpans, - {bool color = false, String primaryColor, String secondaryColor}) { + {bool color = false, String? primaryColor, String? secondaryColor}) { final buffer = StringBuffer() ..write('line ${start.line + 1}, column ${start.column + 1}'); if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}'); @@ -174,7 +174,7 @@ extension SourceSpanExtension on SourceSpan { /// much more useful output with [SourceSpanWithContext]s (including /// [FileSpan]s). String highlightMultiple(String label, Map secondarySpans, - {bool color = false, String primaryColor, String secondaryColor}) => + {bool color = false, String? primaryColor, String? secondaryColor}) => Highlighter.multiple(this, label, secondarySpans, color: color, primaryColor: primaryColor, @@ -183,7 +183,7 @@ extension SourceSpanExtension on SourceSpan { /// Returns a span from [start] code units (inclusive) to [end] code units /// (exclusive) after the beginning of this span. - SourceSpan subspan(int start, [int end]) { + SourceSpan subspan(int start, [int? end]) { RangeError.checkValidRange(start, end, length); if (start == 0 && (end == null || end == length)) return this; @@ -220,7 +220,7 @@ extension SourceSpanExtension on SourceSpan { newEndLocation = this.end; } else if (end == start) { newEndLocation = newStartLocation; - } else if (end != null && end != length) { + } else { for (var i = start; i < end; i++) { consumeCodePoint(i); } diff --git a/pkgs/source_span/lib/src/span_exception.dart b/pkgs/source_span/lib/src/span_exception.dart index 32aaa4eae..c6db03ba2 100644 --- a/pkgs/source_span/lib/src/span_exception.dart +++ b/pkgs/source_span/lib/src/span_exception.dart @@ -15,8 +15,8 @@ class SourceSpanException implements Exception { /// The span associated with this exception. /// /// This may be `null` if the source location can't be determined. - SourceSpan get span => _span; - final SourceSpan _span; + SourceSpan? get span => _span; + final SourceSpan? _span; SourceSpanException(this._message, this._span); @@ -30,7 +30,7 @@ class SourceSpanException implements Exception { @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)}'; } } @@ -41,9 +41,9 @@ class SourceSpanFormatException extends SourceSpanException final dynamic source; @override - int get offset => span?.start?.offset; + int? get offset => span?.start.offset; - SourceSpanFormatException(String message, SourceSpan span, [this.source]) + SourceSpanFormatException(String message, SourceSpan? span, [this.source]) : super(message, span); } @@ -64,7 +64,7 @@ class MultiSourceSpanException extends SourceSpanException { /// additional information and helps distinguish it from [secondarySpans]. final Map secondarySpans; - MultiSourceSpanException(String message, SourceSpan span, this.primaryLabel, + MultiSourceSpanException(String message, SourceSpan? span, this.primaryLabel, Map secondarySpans) : secondarySpans = Map.unmodifiable(secondarySpans), super(message, span); @@ -80,11 +80,11 @@ class MultiSourceSpanException extends SourceSpanException { /// If [color] is `true` or a string, [secondaryColor] is used to highlight /// [secondarySpans]. @override - String toString({color, String secondaryColor}) { + String toString({color, String? secondaryColor}) { if (span == null) return message; var useColor = false; - String primaryColor; + String? primaryColor; if (color is String) { useColor = true; primaryColor = color; @@ -92,7 +92,7 @@ class MultiSourceSpanException extends SourceSpanException { useColor = true; } - final formatted = span.messageMultiple( + final formatted = span!.messageMultiple( message, primaryLabel, secondarySpans, color: useColor, primaryColor: primaryColor, @@ -108,9 +108,9 @@ class MultiSourceSpanFormatException extends MultiSourceSpanException final dynamic source; @override - int get offset => span?.start?.offset; + int? get offset => span?.start.offset; - MultiSourceSpanFormatException(String message, SourceSpan span, + MultiSourceSpanFormatException(String message, SourceSpan? span, String primaryLabel, Map secondarySpans, [this.source]) : super(message, span, primaryLabel, secondarySpans); diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index 55eae94a9..0f751ea52 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -17,7 +17,7 @@ import 'utils.dart'; /// to the distance between [start] and [end]. abstract class SourceSpanMixin implements SourceSpan { @override - Uri get sourceUrl => start.sourceUrl; + Uri? get sourceUrl => start.sourceUrl; @override int get length => end.offset - start.offset; diff --git a/pkgs/source_span/lib/src/utils.dart b/pkgs/source_span/lib/src/utils.dart index 5cb5e90e7..72c61737c 100644 --- a/pkgs/source_span/lib/src/utils.dart +++ b/pkgs/source_span/lib/src/utils.dart @@ -16,10 +16,8 @@ T max(T obj1, T obj2) => /// Returns whether all elements of [iter] are the same value, according to /// `==`. -/// -/// Assumes [iter] doesn't contain any `null` values. bool isAllTheSame(Iterable iter) { - Object lastValue; + Object? lastValue; for (var value in iter) { if (lastValue == null) { lastValue = value; @@ -34,14 +32,14 @@ bool isAllTheSame(Iterable iter) { bool isMultiline(SourceSpan span) => span.start.line != span.end.line; /// Sets the first `null` element of [list] to [element]. -void replaceFirstNull(List list, E element) { +void replaceFirstNull(List list, E element) { final index = list.indexOf(null); if (index < 0) throw ArgumentError('$list contains no null elements.'); list[index] = element; } /// Sets the element of [list] that currently contains [element] to `null`. -void replaceWithNull(List list, E element) { +void replaceWithNull(List list, E element) { final index = list.indexOf(element); if (index < 0) { throw ArgumentError('$list contains no elements matching $element.'); @@ -63,7 +61,7 @@ int countCodeUnits(String string, int codeUnit) { /// /// Returns the index in [context] where that line begins, or null if none /// exists. -int findLineStart(String context, String text, int column) { +int? findLineStart(String context, String text, int column) { // If the text is empty, we just want to find the first line that has at least // [column] characters. if (text.isEmpty) { diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 126d9c09f..89f40c8d7 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,18 +1,92 @@ name: source_span -version: 1.7.0 +version: 1.8.0-nullsafety description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span environment: - sdk: '>=2.6.0 <3.0.0' + sdk: '>=2.9.0-18.0 <2.9.0' dependencies: - charcode: ^1.0.0 - collection: ^1.8.0 - meta: '>=0.9.0 <2.0.0' - path: '>=1.2.0 <2.0.0' - term_glyph: ^1.0.0 + charcode: '>=1.2.0-nullsafety <1.2.0' + collection: '>=1.15.0-nullsafety <1.15.0' + path: '>=1.8.0-nullsafety <1.8.0' + term_glyph: '>=1.2.0-nullsafety <1.2.0' dev_dependencies: test: ^1.6.0 + +dependency_overrides: + async: + git: + url: git://github.com/dart-lang/async.git + ref: null_safety + boolean_selector: + git: + url: git://github.com/dart-lang/boolean_selector.git + ref: null_safety + charcode: + git: + url: git://github.com/dart-lang/charcode.git + ref: null_safety + collection: 1.15.0-nullsafety + js: + git: + url: git://github.com/dart-lang/sdk.git + path: pkg/js + matcher: + git: + url: git://github.com/dart-lang/matcher.git + ref: null_safety + meta: 1.3.0-nullsafety + path: + git: + url: git://github.com/dart-lang/path.git + ref: null_safety + pedantic: + git: + url: git://github.com/dart-lang/pedantic.git + ref: null_safety + pool: + git: + url: git://github.com/dart-lang/pool.git + ref: null_safety + source_maps: + git: + url: git://github.com/dart-lang/source_maps.git + ref: null_safety + source_map_stack_trace: + git: + url: git://github.com/dart-lang/source_map_stack_trace.git + ref: null_safety + stack_trace: + git: + url: git://github.com/dart-lang/stack_trace.git + ref: null_safety + stream_channel: + git: + url: git://github.com/dart-lang/stream_channel.git + ref: null_safety + string_scanner: + git: + url: git://github.com/dart-lang/string_scanner.git + ref: null_safety + term_glyph: + git: + url: git://github.com/dart-lang/term_glyph.git + ref: null_safety + test_api: + git: + url: git://github.com/dart-lang/test.git + ref: null_safety + path: pkgs/test_api + test_core: + git: + url: git://github.com/dart-lang/test.git + ref: null_safety + path: pkgs/test_core + test: + git: + url: git://github.com/dart-lang/test.git + ref: null_safety + path: pkgs/test diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index 63b523f3b..581f03f30 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/test/file_test.dart @@ -6,7 +6,7 @@ import 'package:test/test.dart'; import 'package:source_span/source_span.dart'; void main() { - SourceFile file; + late SourceFile file; setUp(() { file = SourceFile.fromString(''' foo bar baz @@ -295,7 +295,7 @@ zip zap zop }); group('union()', () { - FileSpan span; + late FileSpan span; setUp(() { span = file.span(5, 12); }); @@ -358,7 +358,7 @@ zip zap zop }); group('expand()', () { - FileSpan span; + late FileSpan span; setUp(() { span = file.span(5, 12); }); @@ -407,7 +407,7 @@ zip zap zop }); group('subspan()', () { - FileSpan span; + late FileSpan span; setUp(() { span = file.span(5, 11); // "ar baz" }); diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index 6313108e1..7754d0076 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -10,7 +10,7 @@ import 'package:term_glyph/term_glyph.dart' as glyph; import 'package:test/test.dart'; void main() { - bool oldAscii; + late bool oldAscii; setUpAll(() { oldAscii = glyph.ascii; glyph.ascii = true; @@ -20,7 +20,7 @@ void main() { glyph.ascii = oldAscii; }); - SourceFile file; + late SourceFile file; setUp(() { file = SourceFile.fromString(''' foo bar baz diff --git a/pkgs/source_span/test/location_test.dart b/pkgs/source_span/test/location_test.dart index c22a148c0..bbe259b12 100644 --- a/pkgs/source_span/test/location_test.dart +++ b/pkgs/source_span/test/location_test.dart @@ -6,7 +6,7 @@ import 'package:source_span/source_span.dart'; import 'package:test/test.dart'; void main() { - SourceLocation location; + late SourceLocation location; setUp(() { location = SourceLocation(15, line: 2, column: 6, sourceUrl: 'foo.dart'); }); diff --git a/pkgs/source_span/test/multiple_highlight_test.dart b/pkgs/source_span/test/multiple_highlight_test.dart index d9d1b30c8..6d5ec9d23 100644 --- a/pkgs/source_span/test/multiple_highlight_test.dart +++ b/pkgs/source_span/test/multiple_highlight_test.dart @@ -7,7 +7,7 @@ import 'package:term_glyph/term_glyph.dart' as glyph; import 'package:test/test.dart'; void main() { - bool oldAscii; + late bool oldAscii; setUpAll(() { oldAscii = glyph.ascii; glyph.ascii = true; @@ -17,7 +17,7 @@ void main() { glyph.ascii = oldAscii; }); - SourceFile file; + late SourceFile file; setUp(() { file = SourceFile.fromString(''' foo bar baz diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart index 838d6b7cf..c27048ede 100644 --- a/pkgs/source_span/test/span_test.dart +++ b/pkgs/source_span/test/span_test.dart @@ -9,7 +9,8 @@ import 'package:source_span/source_span.dart'; import 'package:source_span/src/colors.dart' as colors; void main() { - bool oldAscii; + late bool oldAscii; + setUpAll(() { oldAscii = glyph.ascii; glyph.ascii = true; @@ -19,7 +20,7 @@ void main() { glyph.ascii = oldAscii; }); - SourceSpan span; + late SourceSpan span; setUp(() { span = SourceSpan(SourceLocation(5, sourceUrl: 'foo.dart'), SourceLocation(12, sourceUrl: 'foo.dart'), 'foo bar'); diff --git a/pkgs/source_span/test/utils_test.dart b/pkgs/source_span/test/utils_test.dart index a4a372eec..02888dfa1 100644 --- a/pkgs/source_span/test/utils_test.dart +++ b/pkgs/source_span/test/utils_test.dart @@ -9,26 +9,26 @@ void main() { group('find line start', () { test('skip entries in wrong column', () { final context = '0_bb\n1_bbb\n2b____\n3bbb\n'; - final index = findLineStart(context, 'b', 1); + 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', () { final context = '0123\n56789\nabcdefgh\n'; - final index = findLineStart(context, '', 5); + final index = findLineStart(context, '', 5)!; expect(index, 5); expect(context[index], '5'); }); test('column at the end of the file for empty text', () { var context = '0\n2\n45\n'; - var index = findLineStart(context, '', 2); + var index = findLineStart(context, '', 2)!; expect(index, 4); expect(context[index], '4'); context = '0\n2\n45'; - index = findLineStart(context, '', 2); + index = findLineStart(context, '', 2)!; expect(index, 4); }); From bb71863a12c3124d029840dd7a7e7e495891c65b Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Tue, 21 Jul 2020 19:41:25 -0700 Subject: [PATCH 071/128] update for the 2.10 dev sdk (dart-lang/source_span#57) This is in preparation for the actual 2.10 dev sdk release. --- pkgs/source_span/.travis.yml | 12 +++---- pkgs/source_span/pubspec.yaml | 68 +++++++++++++---------------------- 2 files changed, 30 insertions(+), 50 deletions(-) diff --git a/pkgs/source_span/.travis.yml b/pkgs/source_span/.travis.yml index 8361c623e..95f19ae8a 100644 --- a/pkgs/source_span/.travis.yml +++ b/pkgs/source_span/.travis.yml @@ -1,28 +1,28 @@ language: dart dart: -- dev +- preview/raw/2.10.0-0.2-dev jobs: include: - stage: analyze_and_format name: "Analyze test/" - dart: dev + dart: preview/raw/2.10.0-0.2-dev os: linux script: dartanalyzer --enable-experiment=non-nullable --fatal-warnings --fatal-infos . - stage: analyze_and_format name: "Format" - dart: dev + dart: preview/raw/2.10.0-0.2-dev os: linux script: dartfmt -n --set-exit-if-changed . - stage: test name: "Vm Tests" - dart: dev + dart: preview/raw/2.10.0-0.2-dev os: linux script: pub run --enable-experiment=non-nullable test -p vm - stage: test name: "Web Tests" - dart: dev + dart: preview/raw/2.10.0-0.2-dev os: linux script: pub run --enable-experiment=non-nullable test -p chrome @@ -32,7 +32,7 @@ stages: # Only building master means that we don't run two builds for each pull request. branches: - only: [master, null_safety] + only: [master] cache: directories: diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 89f40c8d7..6330c6fd3 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -5,7 +5,8 @@ description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span environment: - sdk: '>=2.9.0-18.0 <2.9.0' + # This must remain a tight constraint until nnbd is stable + sdk: '>=2.10.0-0 <2.10.0' dependencies: charcode: '>=1.2.0-nullsafety <1.2.0' @@ -18,75 +19,54 @@ dev_dependencies: dependency_overrides: async: - git: - url: git://github.com/dart-lang/async.git - ref: null_safety + git: git://github.com/dart-lang/async.git boolean_selector: - git: - url: git://github.com/dart-lang/boolean_selector.git - ref: null_safety + git: git://github.com/dart-lang/boolean_selector.git charcode: - git: - url: git://github.com/dart-lang/charcode.git - ref: null_safety - collection: 1.15.0-nullsafety + git: git://github.com/dart-lang/charcode.git + collection: + git: git://github.com/dart-lang/collection.git js: git: url: git://github.com/dart-lang/sdk.git path: pkg/js + ref: 2-10-pkgs matcher: + git: git://github.com/dart-lang/matcher.git + meta: git: - url: git://github.com/dart-lang/matcher.git - ref: null_safety - meta: 1.3.0-nullsafety + url: git://github.com/dart-lang/sdk.git + path: pkg/meta + ref: 2-10-pkgs path: - git: - url: git://github.com/dart-lang/path.git - ref: null_safety + git: git://github.com/dart-lang/path.git pedantic: - git: - url: git://github.com/dart-lang/pedantic.git - ref: null_safety + git: git://github.com/dart-lang/pedantic.git pool: - git: - url: git://github.com/dart-lang/pool.git - ref: null_safety + git: git://github.com/dart-lang/pool.git source_maps: - git: - url: git://github.com/dart-lang/source_maps.git - ref: null_safety + git: git://github.com/dart-lang/source_maps.git source_map_stack_trace: - git: - url: git://github.com/dart-lang/source_map_stack_trace.git - ref: null_safety + git: git://github.com/dart-lang/source_map_stack_trace.git stack_trace: - git: - url: git://github.com/dart-lang/stack_trace.git - ref: null_safety + git: git://github.com/dart-lang/stack_trace.git stream_channel: - git: - url: git://github.com/dart-lang/stream_channel.git - ref: null_safety + git: git://github.com/dart-lang/stream_channel.git string_scanner: - git: - url: git://github.com/dart-lang/string_scanner.git - ref: null_safety + git: git://github.com/dart-lang/string_scanner.git term_glyph: - git: - url: git://github.com/dart-lang/term_glyph.git - ref: null_safety + git: git://github.com/dart-lang/term_glyph.git test_api: git: url: git://github.com/dart-lang/test.git - ref: null_safety path: pkgs/test_api test_core: git: url: git://github.com/dart-lang/test.git - ref: null_safety path: pkgs/test_core test: git: url: git://github.com/dart-lang/test.git - ref: null_safety path: pkgs/test + typed_data: + git: git://github.com/dart-lang/typed_data.git From d09f50acb992adcbb5ad3af0cfd9c8724c57be23 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Tue, 28 Jul 2020 13:46:00 -0700 Subject: [PATCH 072/128] Delete .test_config No longer used/needed --- pkgs/source_span/.test_config | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 pkgs/source_span/.test_config diff --git a/pkgs/source_span/.test_config b/pkgs/source_span/.test_config deleted file mode 100644 index 412fc5c5c..000000000 --- a/pkgs/source_span/.test_config +++ /dev/null @@ -1,3 +0,0 @@ -{ - "test_package": true -} \ No newline at end of file From 688d2a349c9f1abd683dfc9731c42a928793d847 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Tue, 28 Jul 2020 14:07:23 -0700 Subject: [PATCH 073/128] Update travis-CI to use dev (dart-lang/source_span#58) --- pkgs/source_span/.travis.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pkgs/source_span/.travis.yml b/pkgs/source_span/.travis.yml index 95f19ae8a..8a4761a70 100644 --- a/pkgs/source_span/.travis.yml +++ b/pkgs/source_span/.travis.yml @@ -1,28 +1,24 @@ language: dart dart: -- preview/raw/2.10.0-0.2-dev +- dev jobs: include: - stage: analyze_and_format name: "Analyze test/" - dart: preview/raw/2.10.0-0.2-dev os: linux script: dartanalyzer --enable-experiment=non-nullable --fatal-warnings --fatal-infos . - stage: analyze_and_format name: "Format" - dart: preview/raw/2.10.0-0.2-dev os: linux script: dartfmt -n --set-exit-if-changed . - stage: test name: "Vm Tests" - dart: preview/raw/2.10.0-0.2-dev os: linux script: pub run --enable-experiment=non-nullable test -p vm - stage: test name: "Web Tests" - dart: preview/raw/2.10.0-0.2-dev os: linux script: pub run --enable-experiment=non-nullable test -p chrome From 575c1d08174a7cfd4db03d7359efe49a812e0ecb Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Fri, 4 Sep 2020 09:04:35 -0700 Subject: [PATCH 074/128] fix formatting --- pkgs/source_span/lib/src/highlighter.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 491dae5ba..d61ff9f61 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -288,7 +288,9 @@ class Highlighter { final currentColor = current == null ? null - : current.isPrimary ? _primaryColor : _secondaryColor; + : current.isPrimary + ? _primaryColor + : _secondaryColor; var foundCurrent = false; for (var highlight in highlightsByColumn) { final startLine = highlight?.span.start.line; From 1637967ee783613c792e37891318a601a5d7153f Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Mon, 14 Sep 2020 10:07:56 -0700 Subject: [PATCH 075/128] Work around flow analysis bug (dart-lang/source_span#59) Flow analysis currently has a bug preventing for-each loop variables from being properly promoted in the presence of closures (https://github.com/dart-lang/sdk/issues/43136); as a result of this bug the source_span package had two non-null assertions that ought to have been unnecessary. I'm preparing a fix for that bug, however if I land it as is, it will cause the front end to emit errors saying "Operand of null-aware operation '!' has type '_Highlight' which excludes null"; this in turn will cause SDK bot breakages (since source_span is imported into the SDK repo). So, in order to land the fix, we need to first update the source_span package to work around the bug; this change does that by allocating a temporary variable (which *is* promoted correctly). Once the fix for https://github.com/dart-lang/sdk/issues/43136 lands, I will make a follow-up change that deletes the temporary variable. --- pkgs/source_span/lib/src/highlighter.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index d61ff9f61..1c39185a4 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -292,7 +292,9 @@ class Highlighter { ? _primaryColor : _secondaryColor; var foundCurrent = false; - for (var highlight in highlightsByColumn) { + for (var tmp in highlightsByColumn) { + // Work around https://github.com/dart-lang/sdk/issues/43136 + final highlight = tmp; final startLine = highlight?.span.start.line; final endLine = highlight?.span.end.line; if (current != null && highlight == current) { @@ -326,9 +328,9 @@ class Highlighter { }, color: openedOnThisLineColor); openedOnThisLine = true; openedOnThisLineColor ??= - highlight!.isPrimary ? _primaryColor : _secondaryColor; + highlight.isPrimary ? _primaryColor : _secondaryColor; } else if (endLine == line.number && - highlight!.span.end.column == line.text.length) { + highlight.span.end.column == line.text.length) { _buffer.write(highlight.label == null ? glyph.glyphOrAscii('└', '\\') : vertical); From d851af11e5c521e3210ae2df2b32adeadd263cdc Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Fri, 18 Sep 2020 12:57:11 -0700 Subject: [PATCH 076/128] Prep to release 1.8.0-nullsafety.1 Reverts https://github.com/dart-lang/source_span/pull/59 and removes now unnecessary `!`s. This requires a newer sdk than is available on dev, so run tests on be/raw/latest for now. The dart version in flutter should already be compatible with this version. --- pkgs/source_span/.travis.yml | 2 +- pkgs/source_span/CHANGELOG.md | 4 ++++ pkgs/source_span/lib/src/highlighter.dart | 4 +--- pkgs/source_span/pubspec.yaml | 4 ++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pkgs/source_span/.travis.yml b/pkgs/source_span/.travis.yml index 8a4761a70..290d9a29a 100644 --- a/pkgs/source_span/.travis.yml +++ b/pkgs/source_span/.travis.yml @@ -1,7 +1,7 @@ language: dart dart: -- dev +- be/raw/latest jobs: include: diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 1723b0fc2..b70bc3a36 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.8.0-nullsafety.1 + +* Fixes a newly recognized unnecessary null check to remove warnings. + # 1.8.0-nullsafety * Migrate to null safety. diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 1c39185a4..f622c4e01 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -292,9 +292,7 @@ class Highlighter { ? _primaryColor : _secondaryColor; var foundCurrent = false; - for (var tmp in highlightsByColumn) { - // Work around https://github.com/dart-lang/sdk/issues/43136 - final highlight = tmp; + for (var highlight in highlightsByColumn) { final startLine = highlight?.span.start.line; final endLine = highlight?.span.end.line; if (current != null && highlight == current) { diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 6330c6fd3..597afdf42 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,12 +1,12 @@ name: source_span -version: 1.8.0-nullsafety +version: 1.8.0-nullsafety.1 description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span environment: # This must remain a tight constraint until nnbd is stable - sdk: '>=2.10.0-0 <2.10.0' + sdk: '>=2.10.0-137.0 <2.10.0' dependencies: charcode: '>=1.2.0-nullsafety <1.2.0' From d0e2596b8fd5451cde788a7e1087dfd27b5b8547 Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Mon, 21 Sep 2020 11:26:25 -0700 Subject: [PATCH 077/128] Revert the revert of the flow analysis workaround (dart-lang/source_span#61) * Revert "Prep to release 1.8.0-nullsafety.1" This reverts commit d851af11e5c521e3210ae2df2b32adeadd263cdc. * update pubspec/changelog --- pkgs/source_span/.travis.yml | 2 +- pkgs/source_span/CHANGELOG.md | 4 ++++ pkgs/source_span/lib/src/highlighter.dart | 4 +++- pkgs/source_span/pubspec.yaml | 4 ++-- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pkgs/source_span/.travis.yml b/pkgs/source_span/.travis.yml index 290d9a29a..8a4761a70 100644 --- a/pkgs/source_span/.travis.yml +++ b/pkgs/source_span/.travis.yml @@ -1,7 +1,7 @@ language: dart dart: -- be/raw/latest +- dev jobs: include: diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index b70bc3a36..ba225230b 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.8.0-nullsafety.2-dev + +* Revert unnecessary null check fix (sdk fix wont land in 2.10 stable). + # 1.8.0-nullsafety.1 * Fixes a newly recognized unnecessary null check to remove warnings. diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index f622c4e01..1c39185a4 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -292,7 +292,9 @@ class Highlighter { ? _primaryColor : _secondaryColor; var foundCurrent = false; - for (var highlight in highlightsByColumn) { + for (var tmp in highlightsByColumn) { + // Work around https://github.com/dart-lang/sdk/issues/43136 + final highlight = tmp; final startLine = highlight?.span.start.line; final endLine = highlight?.span.end.line; if (current != null && highlight == current) { diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 597afdf42..76e7b4dcf 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,12 +1,12 @@ name: source_span -version: 1.8.0-nullsafety.1 +version: 1.8.0-nullsafety.2-dev description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span environment: # This must remain a tight constraint until nnbd is stable - sdk: '>=2.10.0-137.0 <2.10.0' + sdk: '>=2.10.0-0.0 <2.10.0' dependencies: charcode: '>=1.2.0-nullsafety <1.2.0' From b37539bcb58280b7f0743d1921832c9aa7535001 Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Mon, 21 Sep 2020 13:20:31 -0700 Subject: [PATCH 078/128] prep to release to unblock flutter (dart-lang/source_span#62) --- pkgs/source_span/CHANGELOG.md | 3 ++- pkgs/source_span/pubspec.yaml | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index ba225230b..4d04b5b42 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,6 +1,7 @@ -# 1.8.0-nullsafety.2-dev +# 1.8.0-nullsafety.2 * Revert unnecessary null check fix (sdk fix wont land in 2.10 stable). +* Allow 2.10 stable and 2.11 dev sdks. # 1.8.0-nullsafety.1 diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 76e7b4dcf..6a3f107da 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,12 +1,12 @@ name: source_span -version: 1.8.0-nullsafety.2-dev +version: 1.8.0-nullsafety.2 description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span environment: # This must remain a tight constraint until nnbd is stable - sdk: '>=2.10.0-0.0 <2.10.0' + sdk: '>=2.10.0-0.0 <2.11.0' dependencies: charcode: '>=1.2.0-nullsafety <1.2.0' From 712d70677d75100e322ec398b1118702dce48ff2 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Tue, 29 Sep 2020 13:25:08 -0700 Subject: [PATCH 079/128] Remove workaround for SDK bug. (dart-lang/source_span#63) Now that https://github.com/dart-lang/sdk/issues/43136 is fixed, the workaround is no longer needed. --- pkgs/source_span/CHANGELOG.md | 5 +++++ pkgs/source_span/lib/src/highlighter.dart | 4 +--- pkgs/source_span/pubspec.yaml | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 4d04b5b42..52c3fb504 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.8.0-nullsafety.3 + +* Remove workaround for https://github.com/dart-lang/sdk/issues/43136, which is + now fixed. + # 1.8.0-nullsafety.2 * Revert unnecessary null check fix (sdk fix wont land in 2.10 stable). diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 1c39185a4..f622c4e01 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -292,9 +292,7 @@ class Highlighter { ? _primaryColor : _secondaryColor; var foundCurrent = false; - for (var tmp in highlightsByColumn) { - // Work around https://github.com/dart-lang/sdk/issues/43136 - final highlight = tmp; + for (var highlight in highlightsByColumn) { final startLine = highlight?.span.start.line; final endLine = highlight?.span.end.line; if (current != null && highlight == current) { diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 6a3f107da..50450fccb 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,12 +1,12 @@ name: source_span -version: 1.8.0-nullsafety.2 +version: 1.8.0-nullsafety.3-dev description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span environment: # This must remain a tight constraint until nnbd is stable - sdk: '>=2.10.0-0.0 <2.11.0' + sdk: '>=2.11.0-0.0 <2.11.0' dependencies: charcode: '>=1.2.0-nullsafety <1.2.0' From 648fcb52ba96c5ea7377f4e0d0b5550860068714 Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Fri, 23 Oct 2020 13:08:34 -0700 Subject: [PATCH 080/128] allow the 2.12 prerelease sdks (dart-lang/source_span#64) --- pkgs/source_span/CHANGELOG.md | 1 + pkgs/source_span/pubspec.yaml | 60 ++--------------------------------- 2 files changed, 4 insertions(+), 57 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 52c3fb504..de8e4ca51 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -2,6 +2,7 @@ * Remove workaround for https://github.com/dart-lang/sdk/issues/43136, which is now fixed. +* Allow prerelease versions of the 2.12 sdk. # 1.8.0-nullsafety.2 diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 50450fccb..2932d1127 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,12 +1,12 @@ name: source_span -version: 1.8.0-nullsafety.3-dev +version: 1.8.0-nullsafety.3 description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span environment: # This must remain a tight constraint until nnbd is stable - sdk: '>=2.11.0-0.0 <2.11.0' + sdk: '>=2.11.0-0.0 <2.12.0' dependencies: charcode: '>=1.2.0-nullsafety <1.2.0' @@ -15,58 +15,4 @@ dependencies: term_glyph: '>=1.2.0-nullsafety <1.2.0' dev_dependencies: - test: ^1.6.0 - -dependency_overrides: - async: - git: git://github.com/dart-lang/async.git - boolean_selector: - git: git://github.com/dart-lang/boolean_selector.git - charcode: - git: git://github.com/dart-lang/charcode.git - collection: - git: git://github.com/dart-lang/collection.git - js: - git: - url: git://github.com/dart-lang/sdk.git - path: pkg/js - ref: 2-10-pkgs - matcher: - git: git://github.com/dart-lang/matcher.git - meta: - git: - url: git://github.com/dart-lang/sdk.git - path: pkg/meta - ref: 2-10-pkgs - path: - git: git://github.com/dart-lang/path.git - pedantic: - git: git://github.com/dart-lang/pedantic.git - pool: - git: git://github.com/dart-lang/pool.git - source_maps: - git: git://github.com/dart-lang/source_maps.git - source_map_stack_trace: - git: git://github.com/dart-lang/source_map_stack_trace.git - stack_trace: - git: git://github.com/dart-lang/stack_trace.git - stream_channel: - git: git://github.com/dart-lang/stream_channel.git - string_scanner: - git: git://github.com/dart-lang/string_scanner.git - term_glyph: - git: git://github.com/dart-lang/term_glyph.git - test_api: - git: - url: git://github.com/dart-lang/test.git - path: pkgs/test_api - test_core: - git: - url: git://github.com/dart-lang/test.git - path: pkgs/test_core - test: - git: - url: git://github.com/dart-lang/test.git - path: pkgs/test - typed_data: - git: git://github.com/dart-lang/typed_data.git + test: ^1.16.0-nullsafety From 5a914124d1ff8bafa1744774dcd973b966606c93 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 3 Nov 2020 14:28:19 -0800 Subject: [PATCH 081/128] Bump SDK constraints for pub (dart-lang/source_span#65) Use a 2.12.0 lower bound since pub does not understand allowed experiments for earlier versions. Use a 3.0.0 upper bound to avoid a warning in pub and to give some flexibility in publishing for stable. --- pkgs/source_span/CHANGELOG.md | 5 +++++ pkgs/source_span/pubspec.yaml | 5 ++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index de8e4ca51..2c812566a 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.8.0-nullsafety.4 + +* Update SDK constraints to `>=2.12.0-0 <3.0.0` based on beta release + guidelines. + # 1.8.0-nullsafety.3 * Remove workaround for https://github.com/dart-lang/sdk/issues/43136, which is diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 2932d1127..a5db06e14 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,12 +1,11 @@ name: source_span -version: 1.8.0-nullsafety.3 +version: 1.8.0-nullsafety.4 description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span environment: - # This must remain a tight constraint until nnbd is stable - sdk: '>=2.11.0-0.0 <2.12.0' + sdk: ">=2.12.0-0.0 <3.0.0" dependencies: charcode: '>=1.2.0-nullsafety <1.2.0' From 778a4bb3bfbbf48da04741381416d7159955b10b Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 3 Nov 2020 16:24:31 -0800 Subject: [PATCH 082/128] Remove dependency on package:charcode (dart-lang/source_span#66) Copy in the charcode constants that are used in this package to a private library. --- pkgs/source_span/CHANGELOG.md | 2 ++ pkgs/source_span/lib/src/charcode.dart | 15 +++++++++++++++ pkgs/source_span/lib/src/highlighter.dart | 2 +- pkgs/source_span/lib/src/span.dart | 2 +- pkgs/source_span/pubspec.yaml | 3 +-- 5 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 pkgs/source_span/lib/src/charcode.dart diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 2c812566a..ae1c0d6ae 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,5 @@ +# 1.8.0-nullsafety.5-dev + # 1.8.0-nullsafety.4 * Update SDK constraints to `>=2.12.0-0 <3.0.0` based on beta release diff --git a/pkgs/source_span/lib/src/charcode.dart b/pkgs/source_span/lib/src/charcode.dart new file mode 100644 index 000000000..51826380a --- /dev/null +++ b/pkgs/source_span/lib/src/charcode.dart @@ -0,0 +1,15 @@ +// Copyright (c) 2020, 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. + +/// "Carriage return" control character. +const int $cr = 0x0D; + +/// "Line feed" control character. +const int $lf = 0x0A; + +/// Space character. +const int $space = 0x20; + +/// "Horizontal Tab" control character, common name. +const int $tab = 0x09; diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index f622c4e01..5d28fc3bb 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -4,11 +4,11 @@ import 'dart:math' as math; -import 'package:charcode/charcode.dart'; import 'package:collection/collection.dart'; import 'package:path/path.dart' as p; import 'package:term_glyph/term_glyph.dart' as glyph; +import 'charcode.dart'; import 'colors.dart' as colors; import 'location.dart'; import 'span.dart'; diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index 94c05ba7a..ba8bec715 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -2,10 +2,10 @@ // 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:charcode/charcode.dart'; import 'package:path/path.dart' as p; import 'package:term_glyph/term_glyph.dart' as glyph; +import 'charcode.dart'; import 'file.dart'; import 'highlighter.dart'; import 'location.dart'; diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index a5db06e14..9f7fca3c2 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.8.0-nullsafety.4 +version: 1.8.0-nullsafety.5-dev description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span @@ -8,7 +8,6 @@ environment: sdk: ">=2.12.0-0.0 <3.0.0" dependencies: - charcode: '>=1.2.0-nullsafety <1.2.0' collection: '>=1.15.0-nullsafety <1.15.0' path: '>=1.8.0-nullsafety <1.8.0' term_glyph: '>=1.2.0-nullsafety <1.2.0' From 35e8cc03c1984e163cd56178449f7efa8cb9d5b7 Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Wed, 11 Nov 2020 10:25:13 -0800 Subject: [PATCH 083/128] remove redundant experiment (dart-lang/source_span#68) --- pkgs/source_span/analysis_options.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkgs/source_span/analysis_options.yaml b/pkgs/source_span/analysis_options.yaml index ced2e21b2..ab5a4f209 100644 --- a/pkgs/source_span/analysis_options.yaml +++ b/pkgs/source_span/analysis_options.yaml @@ -2,8 +2,6 @@ include: package:pedantic/analysis_options.yaml analyzer: strong-mode: implicit-casts: false - enable-experiment: - - non-nullable linter: rules: - always_declare_return_types From 78ba828aecfc0a59bd796c6b5258739f59e8977c Mon Sep 17 00:00:00 2001 From: Alexander Thomas Date: Wed, 20 Jan 2021 18:01:59 +0100 Subject: [PATCH 084/128] Migrate to GitHub Actions (dart-lang/source_span#69) * Migrate to GitHub Actions * Delete .travis.yml --- .../.github/workflows/test-package.yml | 64 +++++++++++++++++++ pkgs/source_span/.travis.yml | 35 ---------- 2 files changed, 64 insertions(+), 35 deletions(-) create mode 100644 pkgs/source_span/.github/workflows/test-package.yml delete mode 100644 pkgs/source_span/.travis.yml diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml new file mode 100644 index 000000000..0a2a87433 --- /dev/null +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -0,0 +1,64 @@ +name: Dart CI + +on: + # Run on PRs and pushes to the default branch. + push: + branches: [ master ] + pull_request: + branches: [ master ] + schedule: + - cron: "0 0 * * 0" + +env: + PUB_ENVIRONMENT: bot.github + +jobs: + # Check code formatting and static analysis on a single OS (linux) + # against Dart dev. + analyze: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + sdk: [dev] + steps: + - uses: actions/checkout@v2 + - uses: dart-lang/setup-dart@v0.3 + with: + sdk: ${{ matrix.sdk }} + - id: install + name: Install dependencies + run: dart pub get + - name: Check formatting + run: dart format --output=none --set-exit-if-changed . + if: always() && steps.install.outcome == 'success' + - name: Analyze code + run: dart analyze --fatal-infos + if: always() && steps.install.outcome == 'success' + + # Run tests on a matrix consisting of two dimensions: + # 1. OS: ubuntu-latest, (macos-latest, windows-latest) + # 2. release channel: dev + test: + needs: analyze + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + # Add macos-latest and/or windows-latest if relevant for this package. + os: [ubuntu-latest] + sdk: [dev] + steps: + - uses: actions/checkout@v2 + - uses: dart-lang/setup-dart@v0.3 + with: + sdk: ${{ matrix.sdk }} + - id: install + name: Install dependencies + run: dart pub get + - name: Run VM tests + run: dart test --platform vm + if: always() && steps.install.outcome == 'success' + - name: Run Chrome tests + run: dart test --platform chrome + if: always() && steps.install.outcome == 'success' diff --git a/pkgs/source_span/.travis.yml b/pkgs/source_span/.travis.yml deleted file mode 100644 index 8a4761a70..000000000 --- a/pkgs/source_span/.travis.yml +++ /dev/null @@ -1,35 +0,0 @@ -language: dart - -dart: -- dev - -jobs: - include: - - stage: analyze_and_format - name: "Analyze test/" - os: linux - script: dartanalyzer --enable-experiment=non-nullable --fatal-warnings --fatal-infos . - - stage: analyze_and_format - name: "Format" - os: linux - script: dartfmt -n --set-exit-if-changed . - - stage: test - name: "Vm Tests" - os: linux - script: pub run --enable-experiment=non-nullable test -p vm - - stage: test - name: "Web Tests" - os: linux - script: pub run --enable-experiment=non-nullable test -p chrome - -stages: - - analyze_and_format - - test - -# Only building master means that we don't run two builds for each pull request. -branches: - only: [master] - -cache: - directories: - - $HOME/.pub-cache From 1ccc5d42328f1ae05f19d329674bea8a5dc954e9 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Mon, 1 Feb 2021 12:18:44 -0800 Subject: [PATCH 085/128] Revert "Remove dependency on package:charcode (dart-lang/source_span#66)" (dart-lang/source_span#70) This reverts commit 778a4bb3bfbbf48da04741381416d7159955b10b. Reverting to keep `lib/` directory content the same as the latest published version. --- pkgs/source_span/CHANGELOG.md | 2 -- pkgs/source_span/lib/src/charcode.dart | 15 --------------- pkgs/source_span/lib/src/highlighter.dart | 2 +- pkgs/source_span/lib/src/span.dart | 2 +- pkgs/source_span/pubspec.yaml | 3 ++- 5 files changed, 4 insertions(+), 20 deletions(-) delete mode 100644 pkgs/source_span/lib/src/charcode.dart diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index ae1c0d6ae..2c812566a 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,5 +1,3 @@ -# 1.8.0-nullsafety.5-dev - # 1.8.0-nullsafety.4 * Update SDK constraints to `>=2.12.0-0 <3.0.0` based on beta release diff --git a/pkgs/source_span/lib/src/charcode.dart b/pkgs/source_span/lib/src/charcode.dart deleted file mode 100644 index 51826380a..000000000 --- a/pkgs/source_span/lib/src/charcode.dart +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2020, 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. - -/// "Carriage return" control character. -const int $cr = 0x0D; - -/// "Line feed" control character. -const int $lf = 0x0A; - -/// Space character. -const int $space = 0x20; - -/// "Horizontal Tab" control character, common name. -const int $tab = 0x09; diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 5d28fc3bb..f622c4e01 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -4,11 +4,11 @@ import 'dart:math' as math; +import 'package:charcode/charcode.dart'; import 'package:collection/collection.dart'; import 'package:path/path.dart' as p; import 'package:term_glyph/term_glyph.dart' as glyph; -import 'charcode.dart'; import 'colors.dart' as colors; import 'location.dart'; import 'span.dart'; diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index ba8bec715..94c05ba7a 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -2,10 +2,10 @@ // 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:charcode/charcode.dart'; import 'package:path/path.dart' as p; import 'package:term_glyph/term_glyph.dart' as glyph; -import 'charcode.dart'; import 'file.dart'; import 'highlighter.dart'; import 'location.dart'; diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 9f7fca3c2..a5db06e14 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.8.0-nullsafety.5-dev +version: 1.8.0-nullsafety.4 description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span @@ -8,6 +8,7 @@ environment: sdk: ">=2.12.0-0.0 <3.0.0" dependencies: + charcode: '>=1.2.0-nullsafety <1.2.0' collection: '>=1.15.0-nullsafety <1.15.0' path: '>=1.8.0-nullsafety <1.8.0' term_glyph: '>=1.2.0-nullsafety <1.2.0' From 8a9af6bded2c393ba2fc847d45cab65d3b014ba8 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 2 Feb 2021 15:41:26 -0800 Subject: [PATCH 086/128] Prepare to publish for stable null safety (dart-lang/source_span#71) --- pkgs/source_span/CHANGELOG.md | 8 ++++++-- pkgs/source_span/pubspec.yaml | 10 +++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 2c812566a..599835fe7 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.8.0 + +* Stable release for null safety. + # 1.8.0-nullsafety.4 * Update SDK constraints to `>=2.12.0-0 <3.0.0` based on beta release @@ -12,7 +16,7 @@ # 1.8.0-nullsafety.2 * Revert unnecessary null check fix (sdk fix wont land in 2.10 stable). -* Allow 2.10 stable and 2.11 dev sdks. +* Allow 2.10 stable and 2.11 dev sdks. # 1.8.0-nullsafety.1 @@ -23,7 +27,7 @@ * Migrate to null safety. * Apis have been migrated to reflect the existing assumptions in the code and are not expected to be breaking. - + # 1.7.0 * Add a `SourceSpan.subspan()` extension method which returns a slice of an diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index a5db06e14..c589022d5 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.8.0-nullsafety.4 +version: 1.8.0 description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span @@ -8,10 +8,10 @@ environment: sdk: ">=2.12.0-0.0 <3.0.0" dependencies: - charcode: '>=1.2.0-nullsafety <1.2.0' - collection: '>=1.15.0-nullsafety <1.15.0' - path: '>=1.8.0-nullsafety <1.8.0' - term_glyph: '>=1.2.0-nullsafety <1.2.0' + charcode: ^1.2.0 + collection: ^1.15.0 + path: ^1.8.0 + term_glyph: ^1.2.0 dev_dependencies: test: ^1.16.0-nullsafety From da6912bc6aa4f55b491c83d4039f7e4656769e4b Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Thu, 4 Feb 2021 11:03:30 -0800 Subject: [PATCH 087/128] Revert "Revert "Remove dependency on package:charcode (dart-lang/source_span#66)" (dart-lang/source_span#70)" (dart-lang/source_span#73) This reverts commit 1ccc5d42328f1ae05f19d329674bea8a5dc954e9. --- pkgs/source_span/CHANGELOG.md | 2 ++ pkgs/source_span/lib/src/charcode.dart | 15 +++++++++++++++ pkgs/source_span/lib/src/highlighter.dart | 2 +- pkgs/source_span/lib/src/span.dart | 2 +- pkgs/source_span/pubspec.yaml | 3 +-- 5 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 pkgs/source_span/lib/src/charcode.dart diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 599835fe7..6f78c4b72 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,5 @@ +# 1.8.1 + # 1.8.0 * Stable release for null safety. diff --git a/pkgs/source_span/lib/src/charcode.dart b/pkgs/source_span/lib/src/charcode.dart new file mode 100644 index 000000000..51826380a --- /dev/null +++ b/pkgs/source_span/lib/src/charcode.dart @@ -0,0 +1,15 @@ +// Copyright (c) 2020, 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. + +/// "Carriage return" control character. +const int $cr = 0x0D; + +/// "Line feed" control character. +const int $lf = 0x0A; + +/// Space character. +const int $space = 0x20; + +/// "Horizontal Tab" control character, common name. +const int $tab = 0x09; diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index f622c4e01..5d28fc3bb 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -4,11 +4,11 @@ import 'dart:math' as math; -import 'package:charcode/charcode.dart'; import 'package:collection/collection.dart'; import 'package:path/path.dart' as p; import 'package:term_glyph/term_glyph.dart' as glyph; +import 'charcode.dart'; import 'colors.dart' as colors; import 'location.dart'; import 'span.dart'; diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index 94c05ba7a..ba8bec715 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -2,10 +2,10 @@ // 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:charcode/charcode.dart'; import 'package:path/path.dart' as p; import 'package:term_glyph/term_glyph.dart' as glyph; +import 'charcode.dart'; import 'file.dart'; import 'highlighter.dart'; import 'location.dart'; diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index c589022d5..12382a5ba 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.8.0 +version: 1.8.1-dev description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span @@ -8,7 +8,6 @@ environment: sdk: ">=2.12.0-0.0 <3.0.0" dependencies: - charcode: ^1.2.0 collection: ^1.15.0 path: ^1.8.0 term_glyph: ^1.2.0 From 313d8597d261bde7d5da4e2cfb40fa55ecfacd7c Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Thu, 4 Feb 2021 11:21:13 -0800 Subject: [PATCH 088/128] Fix header for multispan with null secondary urls (dart-lang/source_span#72) If a multiple span highlight was created where all the secondary spans had `null` URLs they were filtered out from the comparison checking whether multiple files are involved. This bug was caused during the null safety migration. A similar bug previously existed if the primary span had a null URL and is also fixed. - Take a nullable list in `isAllTheSame`. Avoid using `null` as a sentinel for no item seen, use `.first` and `.skip(1)` to compare all elements. - Add tests for the case of primary and secondary spans with a null URL. --- pkgs/source_span/CHANGELOG.md | 3 ++ pkgs/source_span/lib/src/highlighter.dart | 3 +- pkgs/source_span/lib/src/utils.dart | 11 +++-- pkgs/source_span/pubspec.yaml | 2 +- .../test/multiple_highlight_test.dart | 45 ++++++++++++++++--- 5 files changed, 49 insertions(+), 15 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 6f78c4b72..6fda0a058 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,5 +1,8 @@ # 1.8.1 +* Fix a bug where the URL header for the highlights with multiple files would + get omitted only one span has a non-null URI. + # 1.8.0 * Stable release for null safety. diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 5d28fc3bb..19d8965ee 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -107,8 +107,7 @@ class Highlighter { .where((highlight) => isMultiline(highlight.span)) .length) .reduce(math.max), - _multipleFiles = - !isAllTheSame(_lines.map((line) => line.url).whereType()); + _multipleFiles = !isAllTheSame(_lines.map((line) => line.url)); /// Returns whether [lines] contains any adjacent lines from the same source /// file that aren't adjacent in the original file. diff --git a/pkgs/source_span/lib/src/utils.dart b/pkgs/source_span/lib/src/utils.dart index 72c61737c..ccc88bdab 100644 --- a/pkgs/source_span/lib/src/utils.dart +++ b/pkgs/source_span/lib/src/utils.dart @@ -16,12 +16,11 @@ T max(T obj1, T obj2) => /// Returns whether all elements of [iter] are the same value, according to /// `==`. -bool isAllTheSame(Iterable iter) { - Object? lastValue; - for (var value in iter) { - if (lastValue == null) { - lastValue = value; - } else if (value != lastValue) { +bool isAllTheSame(Iterable iter) { + if (iter.isEmpty) return true; + final firstValue = iter.first; + for (var value in iter.skip(1)) { + if (value != firstValue) { return false; } } diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 12382a5ba..89599dfdb 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.8.1-dev +version: 1.8.1 description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span diff --git a/pkgs/source_span/test/multiple_highlight_test.dart b/pkgs/source_span/test/multiple_highlight_test.dart index 6d5ec9d23..b0c28a50a 100644 --- a/pkgs/source_span/test/multiple_highlight_test.dart +++ b/pkgs/source_span/test/multiple_highlight_test.dart @@ -261,14 +261,14 @@ gibble bibble bop }); }); - test('highlights multiple files with their URLs', () { - final file2 = SourceFile.fromString(''' + group('writes headers when highlighting multiple files', () { + test('writes all file URLs', () { + final span2 = SourceFile.fromString(''' quibble bibble boop -''', url: 'file2.txt'); +''', url: 'file2.txt').span(8, 14); - expect( - file.span(31, 34).highlightMultiple('one', {file2.span(8, 14): 'two'}), - equals(""" + expect( + file.span(31, 34).highlightMultiple('one', {span2: 'two'}), equals(""" ,--> file1.txt 3 | zip zap zop | ^^^ one @@ -277,5 +277,38 @@ quibble bibble boop 1 | quibble bibble boop | ====== two '""")); + }); + + test('allows secondary spans to have null URL', () { + final span2 = SourceSpan(SourceLocation(1, sourceUrl: null), + SourceLocation(4, sourceUrl: null), 'foo'); + + expect( + file.span(31, 34).highlightMultiple('one', {span2: 'two'}), equals(""" + ,--> file1.txt +3 | zip zap zop + | ^^^ one + ' + , +1 | foo + | === two + '""")); + }); + + test('allows primary span to have null URL', () { + final span1 = SourceSpan(SourceLocation(1, sourceUrl: null), + SourceLocation(4, sourceUrl: null), 'foo'); + + expect( + span1.highlightMultiple('one', {file.span(31, 34): 'two'}), equals(""" + , +1 | foo + | ^^^ one + ' + ,--> file1.txt +3 | zip zap zop + | === two + '""")); + }); }); } From 8d79ded38d38ee92cff620cd287da9f5e2157d80 Mon Sep 17 00:00:00 2001 From: Franklin Yow <58489007+franklinyow@users.noreply.github.com> Date: Wed, 31 Mar 2021 15:58:32 -0700 Subject: [PATCH 089/128] Update LICENSE (dart-lang/source_span#75) --- pkgs/source_span/LICENSE | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/LICENSE b/pkgs/source_span/LICENSE index 5c60afea3..000cd7bec 100644 --- a/pkgs/source_span/LICENSE +++ b/pkgs/source_span/LICENSE @@ -1,4 +1,5 @@ -Copyright 2014, the Dart project authors. All rights reserved. +Copyright 2014, the Dart project authors. + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -9,7 +10,7 @@ met: copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Google Inc. nor the names of its + * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. From 1b5cba3eba88966f843378429399f68f8258a888 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Mon, 26 Apr 2021 10:20:02 -0700 Subject: [PATCH 090/128] fix lint (dart-lang/source_span#76) * Fix newly enforced lint * pubspec and CI cleanup --- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- pkgs/source_span/CHANGELOG.md | 2 ++ pkgs/source_span/pubspec.yaml | 6 +++--- pkgs/source_span/test/file_test.dart | 2 +- pkgs/source_span/test/span_test.dart | 5 ++--- pkgs/source_span/test/utils_test.dart | 2 +- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 0a2a87433..8c20eeb6d 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@v2 - - uses: dart-lang/setup-dart@v0.3 + - uses: dart-lang/setup-dart@v1.0 with: sdk: ${{ matrix.sdk }} - id: install @@ -50,7 +50,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@v2 - - uses: dart-lang/setup-dart@v0.3 + - uses: dart-lang/setup-dart@v1.0 with: sdk: ${{ matrix.sdk }} - id: install diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 6fda0a058..fa4b193c1 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,5 @@ +# 1.8.2-dev + # 1.8.1 * Fix a bug where the URL header for the highlights with multiple files would diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 89599dfdb..3343428f3 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,11 +1,11 @@ name: source_span -version: 1.8.1 +version: 1.8.2-dev description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span environment: - sdk: ">=2.12.0-0.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: collection: ^1.15.0 @@ -13,4 +13,4 @@ dependencies: term_glyph: ^1.2.0 dev_dependencies: - test: ^1.16.0-nullsafety + test: ^1.16.0 diff --git a/pkgs/source_span/test/file_test.dart b/pkgs/source_span/test/file_test.dart index 581f03f30..dff51ee28 100644 --- a/pkgs/source_span/test/file_test.dart +++ b/pkgs/source_span/test/file_test.dart @@ -2,8 +2,8 @@ // 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'; void main() { late SourceFile file; diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart index c27048ede..348cc9e7d 100644 --- a/pkgs/source_span/test/span_test.dart +++ b/pkgs/source_span/test/span_test.dart @@ -2,11 +2,10 @@ // 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:term_glyph/term_glyph.dart' as glyph; - 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'; void main() { late bool oldAscii; diff --git a/pkgs/source_span/test/utils_test.dart b/pkgs/source_span/test/utils_test.dart index 02888dfa1..293b30023 100644 --- a/pkgs/source_span/test/utils_test.dart +++ b/pkgs/source_span/test/utils_test.dart @@ -2,8 +2,8 @@ // 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/src/utils.dart'; +import 'package:test/test.dart'; void main() { group('find line start', () { From 0569ed0b8a6551c87581d33da6e8ed2c81d7e28e Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Mon, 4 Oct 2021 13:14:26 -0700 Subject: [PATCH 091/128] Fix broken lints, update to pkg:lints, Bump SDK constraint (dart-lang/source_span#77) Also cleaned out changelog --- pkgs/source_span/CHANGELOG.md | 28 ++------------------ pkgs/source_span/analysis_options.yaml | 4 ++- pkgs/source_span/lib/src/file.dart | 5 ++-- pkgs/source_span/lib/src/location.dart | 4 +-- pkgs/source_span/lib/src/location_mixin.dart | 4 +-- pkgs/source_span/lib/src/span.dart | 2 +- pkgs/source_span/lib/src/span_mixin.dart | 4 +-- pkgs/source_span/pubspec.yaml | 3 ++- 8 files changed, 16 insertions(+), 38 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index fa4b193c1..90aba0b6b 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,5 +1,7 @@ # 1.8.2-dev +- Require Dart >= 2.14. + # 1.8.1 * Fix a bug where the URL header for the highlights with multiple files would @@ -9,32 +11,6 @@ * Stable release for null safety. -# 1.8.0-nullsafety.4 - -* Update SDK constraints to `>=2.12.0-0 <3.0.0` based on beta release - guidelines. - -# 1.8.0-nullsafety.3 - -* Remove workaround for https://github.com/dart-lang/sdk/issues/43136, which is - now fixed. -* Allow prerelease versions of the 2.12 sdk. - -# 1.8.0-nullsafety.2 - -* Revert unnecessary null check fix (sdk fix wont land in 2.10 stable). -* Allow 2.10 stable and 2.11 dev sdks. - -# 1.8.0-nullsafety.1 - -* Fixes a newly recognized unnecessary null check to remove warnings. - -# 1.8.0-nullsafety - -* Migrate to null safety. - * Apis have been migrated to reflect the existing assumptions in the code - and are not expected to be breaking. - # 1.7.0 * Add a `SourceSpan.subspan()` extension method which returns a slice of an diff --git a/pkgs/source_span/analysis_options.yaml b/pkgs/source_span/analysis_options.yaml index ab5a4f209..002297f45 100644 --- a/pkgs/source_span/analysis_options.yaml +++ b/pkgs/source_span/analysis_options.yaml @@ -1,7 +1,9 @@ -include: package:pedantic/analysis_options.yaml +include: package:lints/recommended.yaml + analyzer: strong-mode: implicit-casts: false + linter: rules: - always_declare_return_types diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 6fbcd4193..473b8c17a 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -398,9 +398,8 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { sourceUrl == other.sourceUrl; } - // Eliminates dart2js warning about overriding `==`, but not `hashCode` @override - int get hashCode => super.hashCode; + int get hashCode => Object.hash(_start, _end, sourceUrl); /// Returns a new span that covers both `this` and [other]. /// @@ -409,7 +408,7 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { @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."); } diff --git a/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart index 097961841..634863bf0 100644 --- a/pkgs/source_span/lib/src/location.dart +++ b/pkgs/source_span/lib/src/location.dart @@ -61,7 +61,7 @@ class SourceLocation implements Comparable { /// 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(); @@ -76,7 +76,7 @@ class SourceLocation implements Comparable { @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; diff --git a/pkgs/source_span/lib/src/location_mixin.dart b/pkgs/source_span/lib/src/location_mixin.dart index 9a1f930f8..bae38befa 100644 --- a/pkgs/source_span/lib/src/location_mixin.dart +++ b/pkgs/source_span/lib/src/location_mixin.dart @@ -23,7 +23,7 @@ abstract class SourceLocationMixin implements SourceLocation { @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(); @@ -35,7 +35,7 @@ abstract class SourceLocationMixin implements SourceLocation { @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; diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index ba8bec715..30590ea88 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -102,7 +102,7 @@ class SourceSpanBase extends SourceSpanMixin { SourceSpanBase(this.start, this.end, this.text) { if (end.sourceUrl != start.sourceUrl) { - throw ArgumentError('Source URLs \"${start.sourceUrl}\" and ' + throw ArgumentError('Source URLs "${start.sourceUrl}" and ' " \"${end.sourceUrl}\" don't match."); } else if (end.offset < start.offset) { throw ArgumentError('End $end must come after start $start.'); diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index 0f751ea52..4d7bab473 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -31,7 +31,7 @@ abstract class SourceSpanMixin implements SourceSpan { @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."); } @@ -77,7 +77,7 @@ abstract class SourceSpanMixin implements SourceSpan { other is SourceSpan && start == other.start && end == other.end; @override - int get hashCode => start.hashCode + (31 * end.hashCode); + int get hashCode => Object.hash(start, end); @override String toString() => '<$runtimeType: from $start to $end "$text">'; diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 3343428f3..08bf64b8d 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -5,7 +5,7 @@ description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.14.0 <3.0.0" dependencies: collection: ^1.15.0 @@ -13,4 +13,5 @@ dependencies: term_glyph: ^1.2.0 dev_dependencies: + lints: ^1.0.0 test: ^1.16.0 From c1305da5849ed0d97e3a2a1033a8ee0e7ccc7748 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 22 Dec 2021 16:05:27 -0800 Subject: [PATCH 092/128] Don't crash when highlighting multiple spans with null URLs (dart-lang/source_span#78) --- pkgs/source_span/CHANGELOG.md | 6 ++-- pkgs/source_span/lib/src/highlighter.dart | 33 +++++++++++-------- pkgs/source_span/pubspec.yaml | 2 +- .../test/multiple_highlight_test.dart | 17 ++++++++++ 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 90aba0b6b..c0096b7ea 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,6 +1,8 @@ -# 1.8.2-dev +# 1.8.2 -- Require Dart >= 2.14. +* Fix a bug where highlighting multiple spans with `null` URLs could cause an + assertion error. Now when multiple spans are passed with `null` URLs, they're + highlighted as though they all come from different source files. # 1.8.1 diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 19d8965ee..d4e5ebf0e 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -126,14 +126,20 @@ class Highlighter { /// Collect all the source lines from the contexts of all spans in /// [highlights], and associates them with the highlights that cover them. static List<_Line> _collateLines(List<_Highlight> highlights) { - final highlightsByUrl = groupBy<_Highlight, Uri?>( - highlights, (highlight) => highlight.span.sourceUrl); + // Assign spans without URLs opaque Objects as keys. Each such Object will + // be different, but they can then be used later on to determine which lines + // came from the same span even if they'd all otherwise have `null` URLs. + final highlightsByUrl = groupBy<_Highlight, Object>( + highlights, (highlight) => highlight.span.sourceUrl ?? Object()); for (var list in highlightsByUrl.values) { list.sort((highlight1, highlight2) => highlight1.span.compareTo(highlight2.span)); } - return highlightsByUrl.values.expand((highlightsForFile) { + return highlightsByUrl.entries.expand((entry) { + final url = entry.key; + final highlightsForFile = entry.value; + // First, create a list of all the lines in the current file that we have // context for along with their line numbers. final lines = <_Line>[]; @@ -147,7 +153,6 @@ class Highlighter { final linesBeforeSpan = '\n'.allMatches(context.substring(0, lineStart)).length; - final url = highlight.span.sourceUrl; var lineNumber = highlight.span.start.line - linesBeforeSpan; for (var line in context.split('\n')) { // Only add a line if it hasn't already been added for a previous span. @@ -162,14 +167,12 @@ class Highlighter { final activeHighlights = <_Highlight>[]; var highlightIndex = 0; for (var line in lines) { - activeHighlights.removeWhere((highlight) => - highlight.span.sourceUrl != line.url || - highlight.span.end.line < line.number); + activeHighlights + .removeWhere((highlight) => highlight.span.end.line < line.number); final oldHighlightLength = activeHighlights.length; for (var highlight in highlightsForFile.skip(highlightIndex)) { if (highlight.span.start.line > line.number) break; - if (highlight.span.sourceUrl != line.url) break; activeHighlights.add(highlight); } highlightIndex += activeHighlights.length - oldHighlightLength; @@ -258,9 +261,9 @@ class Highlighter { } /// Writes the beginning of the file highlight for the file with the given - /// [url]. - void _writeFileStart(Uri? url) { - if (!_multipleFiles || url == null) { + /// [url] (or opaque object if it comes from a span with a null URL). + void _writeFileStart(Object url) { + if (!_multipleFiles || url is! Uri) { _writeSidebar(end: glyph.downEnd); } else { _writeSidebar(end: glyph.topLeftCorner); @@ -409,7 +412,8 @@ class Highlighter { /// of [character]. void _writeUnderline(_Line line, SourceSpan span, String character) { assert(!isMultiline(span)); - assert(line.text.contains(span.text)); + assert(line.text.contains(span.text), + '"${line.text}" should contain "${span.text}"'); var startColumn = span.start.column; var endColumn = span.end.column; @@ -664,7 +668,10 @@ class _Line { final int number; /// The URL of the source file in which this line appears. - final Uri? url; + /// + /// For lines created from spans without an explicit URL, this is an opaque + /// object that differs between lines that come from different spans. + final Object url; /// All highlights that cover any portion of this line, in source span order. /// diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 08bf64b8d..ad81db6be 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.8.2-dev +version: 1.8.2 description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span diff --git a/pkgs/source_span/test/multiple_highlight_test.dart b/pkgs/source_span/test/multiple_highlight_test.dart index b0c28a50a..a9f5fdac4 100644 --- a/pkgs/source_span/test/multiple_highlight_test.dart +++ b/pkgs/source_span/test/multiple_highlight_test.dart @@ -311,4 +311,21 @@ quibble bibble boop '""")); }); }); + + test('highlights multiple null URLs as separate files', () { + final span1 = SourceSpan(SourceLocation(1, sourceUrl: null), + SourceLocation(4, sourceUrl: null), 'foo'); + final span2 = SourceSpan(SourceLocation(1, sourceUrl: null), + SourceLocation(4, sourceUrl: null), 'bar'); + + expect(span1.highlightMultiple('one', {span2: 'two'}), equals(""" + , +1 | foo + | ^^^ one + ' + , +1 | bar + | === two + '""")); + }); } From f9bc8902f6a5959ad5829a14438a7d930bbdf62f Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Tue, 5 Apr 2022 15:56:33 -0700 Subject: [PATCH 093/128] Add SourceSpanWithContextExtension.subspan (dart-lang/source_span#81) --- pkgs/source_span/CHANGELOG.md | 5 ++ pkgs/source_span/lib/src/span.dart | 47 ++-------------- .../lib/src/span_with_context.dart | 15 ++++++ pkgs/source_span/lib/src/utils.dart | 54 +++++++++++++++++++ pkgs/source_span/pubspec.yaml | 2 +- pkgs/source_span/test/span_test.dart | 7 +++ 6 files changed, 85 insertions(+), 45 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index c0096b7ea..f906a87a6 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.9.0 + +* Add `SourceSpanWithContextExtension.subspan` that returns a + `SourceSpanWithContext` rather than a plain `SourceSpan`. + # 1.8.2 * Fix a bug where highlighting multiple spans with `null` URLs could cause an diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index 30590ea88..05fd340a2 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -5,12 +5,12 @@ import 'package:path/path.dart' as p; import 'package:term_glyph/term_glyph.dart' as glyph; -import 'charcode.dart'; import 'file.dart'; import 'highlighter.dart'; import 'location.dart'; import 'span_mixin.dart'; import 'span_with_context.dart'; +import 'utils.dart'; /// A class that describes a segment of source text. abstract class SourceSpan implements Comparable { @@ -187,48 +187,7 @@ extension SourceSpanExtension on SourceSpan { RangeError.checkValidRange(start, end, length); if (start == 0 && (end == null || end == length)) return this; - final text = this.text; - final startLocation = this.start; - var line = startLocation.line; - var column = startLocation.column; - - // Adjust [line] and [column] as necessary if the character at [i] in [text] - // is a newline. - void consumeCodePoint(int i) { - final codeUnit = text.codeUnitAt(i); - if (codeUnit == $lf || - // A carriage return counts as a newline, but only if it's not - // followed by a line feed. - (codeUnit == $cr && - (i + 1 == text.length || text.codeUnitAt(i + 1) != $lf))) { - line += 1; - column = 0; - } else { - column += 1; - } - } - - for (var i = 0; i < start; i++) { - consumeCodePoint(i); - } - - final newStartLocation = SourceLocation(startLocation.offset + start, - sourceUrl: sourceUrl, line: line, column: column); - - SourceLocation newEndLocation; - if (end == null || end == length) { - newEndLocation = this.end; - } else if (end == start) { - newEndLocation = newStartLocation; - } else { - for (var i = start; i < end; i++) { - consumeCodePoint(i); - } - newEndLocation = SourceLocation(startLocation.offset + end, - sourceUrl: sourceUrl, line: line, column: column); - } - - return SourceSpan( - newStartLocation, newEndLocation, text.substring(start, end)); + final locations = subspanLocations(this, start, end); + return SourceSpan(locations[0], locations[1], text.substring(start, end)); } } diff --git a/pkgs/source_span/lib/src/span_with_context.dart b/pkgs/source_span/lib/src/span_with_context.dart index da09cc0b8..776c78988 100644 --- a/pkgs/source_span/lib/src/span_with_context.dart +++ b/pkgs/source_span/lib/src/span_with_context.dart @@ -34,3 +34,18 @@ class SourceSpanWithContext extends SourceSpanBase { } } } + +// TODO(#52): Move these to instance methods in the next breaking release. +/// Extension methods on the base [SourceSpan] API. +extension SourceSpanWithContextExtension on SourceSpanWithContext { + /// Returns a span from [start] code units (inclusive) to [end] code units + /// (exclusive) after the beginning of this span. + SourceSpanWithContext subspan(int start, [int? end]) { + RangeError.checkValidRange(start, end, length); + if (start == 0 && (end == null || end == length)) return this; + + final locations = subspanLocations(this, start, end); + return SourceSpanWithContext( + locations[0], locations[1], text.substring(start, end), context); + } +} diff --git a/pkgs/source_span/lib/src/utils.dart b/pkgs/source_span/lib/src/utils.dart index ccc88bdab..7df0bafca 100644 --- a/pkgs/source_span/lib/src/utils.dart +++ b/pkgs/source_span/lib/src/utils.dart @@ -2,7 +2,10 @@ // 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 'charcode.dart'; +import 'location.dart'; import 'span.dart'; +import 'span_with_context.dart'; /// Returns the minimum of [obj1] and [obj2] according to /// [Comparable.compareTo]. @@ -89,3 +92,54 @@ int? findLineStart(String context, String text, int column) { // ignore: avoid_returning_null return null; } + +/// Returns a two-element list containing the start and end locations of the +/// span from [start] code units (inclusive) to [end] code units (exclusive) +/// after the beginning of [span]. +/// +/// This is factored out so it can be shared between +/// [SourceSpanExtension.subspan] and [SourceSpanWithContextExtension.subspan]. +List subspanLocations(SourceSpan span, int start, [int? end]) { + final text = span.text; + final startLocation = span.start; + var line = startLocation.line; + var column = startLocation.column; + + // Adjust [line] and [column] as necessary if the character at [i] in [text] + // is a newline. + void consumeCodePoint(int i) { + final codeUnit = text.codeUnitAt(i); + if (codeUnit == $lf || + // A carriage return counts as a newline, but only if it's not + // followed by a line feed. + (codeUnit == $cr && + (i + 1 == text.length || text.codeUnitAt(i + 1) != $lf))) { + line += 1; + column = 0; + } else { + column += 1; + } + } + + for (var i = 0; i < start; i++) { + consumeCodePoint(i); + } + + final newStartLocation = SourceLocation(startLocation.offset + start, + sourceUrl: span.sourceUrl, line: line, column: column); + + SourceLocation newEndLocation; + if (end == null || end == span.length) { + newEndLocation = span.end; + } else if (end == start) { + newEndLocation = newStartLocation; + } else { + for (var i = start; i < end; i++) { + consumeCodePoint(i); + } + newEndLocation = SourceLocation(startLocation.offset + end, + sourceUrl: span.sourceUrl, line: line, column: column); + } + + return [newStartLocation, newEndLocation]; +} diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index ad81db6be..84db52e24 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.8.2 +version: 1.9.0 description: A library for identifying source spans and locations. homepage: https://github.com/dart-lang/source_span diff --git a/pkgs/source_span/test/span_test.dart b/pkgs/source_span/test/span_test.dart index 348cc9e7d..22c498efb 100644 --- a/pkgs/source_span/test/span_test.dart +++ b/pkgs/source_span/test/span_test.dart @@ -206,6 +206,13 @@ void main() { expect(result.end.sourceUrl, equals(span.sourceUrl)); }); + test('preserves the context', () { + final start = SourceLocation(2); + final end = SourceLocation(5); + final span = SourceSpanWithContext(start, end, 'abc', '--abc--'); + expect(span.subspan(1, 2).context, equals('--abc--')); + }); + group('returns the original span', () { test('with an implicit end', () => expect(span.subspan(0), equals(span))); From 4db895023a0cba08501d97c8c358d088449ec270 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Tue, 3 May 2022 15:13:01 -0700 Subject: [PATCH 094/128] populate the pubspec repository field (dart-lang/source_span#82) --- pkgs/source_span/CHANGELOG.md | 4 ++++ pkgs/source_span/README.md | 4 ++++ pkgs/source_span/pubspec.yaml | 5 ++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index f906a87a6..5722045c2 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.9.1-dev + +* Populate the pubspec `repository` field. + # 1.9.0 * Add `SourceSpanWithContextExtension.subspan` that returns a diff --git a/pkgs/source_span/README.md b/pkgs/source_span/README.md index 4e2547e28..be91debd0 100644 --- a/pkgs/source_span/README.md +++ b/pkgs/source_span/README.md @@ -1,3 +1,7 @@ +[![Dart CI](https://github.com/dart-lang/source_span/actions/workflows/test-package.yml/badge.svg)](https://github.com/dart-lang/source_span/actions/workflows/test-package.yml) +[![pub package](https://img.shields.io/pub/v/source_span.svg)](https://pub.dev/packages/source_span) +[![package publisher](https://img.shields.io/pub/publisher/source_span.svg)](https://pub.dev/packages/source_span/publisher) + `source_span` is a library for tracking locations in source code. It's designed to provide a standard representation for source code locations and spans so that disparate packages can easily pass them among one another, and to make it easy diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 84db52e24..63a64b09c 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,8 +1,7 @@ name: source_span -version: 1.9.0 - +version: 1.9.1-dev description: A library for identifying source spans and locations. -homepage: https://github.com/dart-lang/source_span +repository: https://github.com/dart-lang/source_span environment: sdk: ">=2.14.0 <3.0.0" From 3c857aba528b75f86d3c1af3c11a4e05efc8f397 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 20 Jul 2022 16:07:36 -0700 Subject: [PATCH 095/128] Properly indent multi-line labels for mutli-span highlights (dart-lang/source_span#86) --- pkgs/source_span/CHANGELOG.md | 4 +- pkgs/source_span/analysis_options.yaml | 1 - pkgs/source_span/lib/src/highlighter.dart | 66 ++++++++++--- pkgs/source_span/pubspec.yaml | 2 +- .../test/multiple_highlight_test.dart | 96 +++++++++++++++++++ 5 files changed, 153 insertions(+), 16 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 5722045c2..4c4907906 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,4 +1,6 @@ -# 1.9.1-dev +# 1.9.1 + +* Properly handle multi-line labels for multi-span highlights. * Populate the pubspec `repository` field. diff --git a/pkgs/source_span/analysis_options.yaml b/pkgs/source_span/analysis_options.yaml index 002297f45..97c0552ff 100644 --- a/pkgs/source_span/analysis_options.yaml +++ b/pkgs/source_span/analysis_options.yaml @@ -39,7 +39,6 @@ linter: - file_names - hash_and_equals - implementation_imports - - invariant_booleans - iterable_contains_unrelated_type - library_names - library_prefixes diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index d4e5ebf0e..53f3d6377 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -367,12 +367,13 @@ class Highlighter { _writeMultilineHighlights(line, highlightsByColumn, current: highlight); if (highlightsByColumn.isNotEmpty) _buffer.write(' '); - _colorize(() { + final underlineLength = _colorize(() { + final start = _buffer.length; _writeUnderline(line, highlight.span, highlight.isPrimary ? '^' : glyph.horizontalLineBold); - _writeLabel(highlight.label); + return _buffer.length - start; }, color: color); - _buffer.writeln(); + _writeLabel(highlight, highlightsByColumn, underlineLength); } else if (highlight.span.start.line == line.number) { if (highlightsByColumn.contains(highlight)) return; replaceFirstNull(highlightsByColumn, highlight); @@ -394,16 +395,17 @@ class Highlighter { _buffer.write(' '); _writeMultilineHighlights(line, highlightsByColumn, current: highlight); - _colorize(() { + final underlineLength = _colorize(() { + final start = _buffer.length; if (coversWholeLine) { _buffer.write(glyph.horizontalLine * 3); } else { _writeArrow(line, math.max(highlight.span.end.column - 1, 0), beginning: false); } - _writeLabel(highlight.label); + return _buffer.length - start; }, color: color); - _buffer.writeln(); + _writeLabel(highlight, highlightsByColumn, underlineLength); replaceWithNull(highlightsByColumn, highlight); } } @@ -442,9 +444,45 @@ class Highlighter { ..write('^'); } - /// Writes a space followed by [label] if [label] isn't `null`. - void _writeLabel(String? label) { - if (label != null) _buffer.write(' $label'); + /// Writes [highlight]'s label. + /// + /// The `_buffer` is assumed to be written to the point where the first line + /// of `highlight.label` can be written after a space, but this takes care of + /// writing indentation and highlight columns for later lines. + /// + /// The [highlightsByColumn] are used to write ongoing highlight lines if the + /// label is more than one line long. + /// + /// The [underlineLength] is the length of the line written between the + /// highlights and the beginning of the first label. + void _writeLabel(_Highlight highlight, List<_Highlight?> highlightsByColumn, + int underlineLength) { + final label = highlight.label; + if (label == null) { + _buffer.writeln(); + return; + } + + final lines = label.split('\n'); + final color = highlight.isPrimary ? _primaryColor : _secondaryColor; + _colorize(() => _buffer.write(' ${lines.first}'), color: color); + _buffer.writeln(); + + for (var text in lines.skip(1)) { + _writeSidebar(); + _buffer.write(' '); + for (var columnHighlight in highlightsByColumn) { + if (columnHighlight == null || columnHighlight == highlight) { + _buffer.write(' '); + } else { + _buffer.write(glyph.verticalLine); + } + } + + _buffer.write(' ' * underlineLength); + _colorize(() => _buffer.write(' $text'), color: color); + _buffer.writeln(); + } } /// Writes a snippet from the source text, converting hard tab characters into @@ -496,10 +534,11 @@ class Highlighter { /// Colors all text written to [_buffer] during [callback], if colorization is /// enabled and [color] is not `null`. - void _colorize(void Function() callback, {required String? color}) { + T _colorize(T Function() callback, {required String? color}) { if (_primaryColor != null && color != null) _buffer.write(color); - callback(); + final result = callback(); if (_primaryColor != null && color != null) _buffer.write(colors.none); + return result; } } @@ -522,14 +561,15 @@ class _Highlight { /// used in the same message. final String? label; - _Highlight(SourceSpan span, {this.label, bool primary = false}) + _Highlight(SourceSpan span, {String? label, bool primary = false}) : span = (() { var newSpan = _normalizeContext(span); newSpan = _normalizeNewlines(newSpan); newSpan = _normalizeTrailingNewline(newSpan); return _normalizeEndOfLine(newSpan); })(), - isPrimary = primary; + isPrimary = primary, + label = label?.replaceAll('\r\n', '\n'); /// Normalizes [span] to ensure that it's a [SourceSpanWithContext] whose /// context actually contains its text at the expected column. diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 63a64b09c..8bde1c281 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.9.1-dev +version: 1.9.1 description: A library for identifying source spans and locations. repository: https://github.com/dart-lang/source_span diff --git a/pkgs/source_span/test/multiple_highlight_test.dart b/pkgs/source_span/test/multiple_highlight_test.dart index a9f5fdac4..ba4d686b3 100644 --- a/pkgs/source_span/test/multiple_highlight_test.dart +++ b/pkgs/source_span/test/multiple_highlight_test.dart @@ -328,4 +328,100 @@ quibble bibble boop | === two '""")); }); + + group('indents mutli-line labels', () { + test('for the primary label', () { + expect(file.span(17, 21).highlightMultiple('line 1\nline 2\nline 3', {}), + equals(""" + , +2 | whiz bang boom + | ^^^^ line 1 + | line 2 + | line 3 + '""")); + }); + + group('for a secondary label', () { + test('on the same line', () { + expect( + file.span(17, 21).highlightMultiple( + 'primary', {file.span(22, 26): 'line 1\nline 2\nline 3'}), + equals(""" + , +2 | whiz bang boom + | ^^^^ primary + | ==== line 1 + | line 2 + | line 3 + '""")); + }); + + test('on a different line', () { + expect( + file.span(17, 21).highlightMultiple( + 'primary', {file.span(31, 34): 'line 1\nline 2\nline 3'}), + equals(""" + , +2 | whiz bang boom + | ^^^^ primary +3 | zip zap zop + | === line 1 + | line 2 + | line 3 + '""")); + }); + }); + + group('for a multiline span', () { + test('that covers the whole last line', () { + expect( + file.span(12, 70).highlightMultiple('line 1\nline 2\nline 3', {}), + equals(""" + , +2 | / whiz bang boom +3 | | zip zap zop +4 | | fwee fwoo fwip +5 | | argle bargle boo + | '--- line 1 + | line 2 + | line 3 + '""")); + }); + + test('that covers part of the last line', () { + expect( + file.span(12, 66).highlightMultiple('line 1\nline 2\nline 3', {}), + equals(""" + , +2 | / whiz bang boom +3 | | zip zap zop +4 | | fwee fwoo fwip +5 | | argle bargle boo + | '------------^ line 1 + | line 2 + | line 3 + '""")); + }); + }); + + test('with an overlapping span', () { + expect( + file.span(12, 70).highlightMultiple('line 1\nline 2\nline 3', + {file.span(54, 89): 'two', file.span(0, 27): 'three'}), + equals(""" + , +1 | /- foo bar baz +2 | |/ whiz bang boom + | '+--- three +3 | | zip zap zop +4 | | fwee fwoo fwip +5 | /+ argle bargle boo + | |'--- line 1 + | | line 2 + | | line 3 +6 | | gibble bibble bop + | '---- two + '""")); + }); + }); } From 013c00fda144cfba74303fd237d1a73731dadd60 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Tue, 25 Oct 2022 10:24:43 -0700 Subject: [PATCH 096/128] Require Dart 2.18, update lints, latest pkg:lints, add dependabot (dart-lang/source_span#88) --- pkgs/source_span/.github/dependabot.yml | 10 +++ .../.github/workflows/test-package.yml | 10 +-- pkgs/source_span/CHANGELOG.md | 4 + pkgs/source_span/analysis_options.yaml | 87 ++++++------------- pkgs/source_span/lib/src/file.dart | 10 +-- pkgs/source_span/lib/src/highlighter.dart | 24 ++--- pkgs/source_span/lib/src/location.dart | 7 +- pkgs/source_span/lib/src/location_mixin.dart | 2 +- pkgs/source_span/lib/src/span.dart | 4 +- pkgs/source_span/lib/src/span_exception.dart | 19 ++-- pkgs/source_span/lib/src/span_mixin.dart | 6 +- pkgs/source_span/lib/src/utils.dart | 4 +- pkgs/source_span/pubspec.yaml | 6 +- pkgs/source_span/test/highlight_test.dart | 40 ++++----- .../test/multiple_highlight_test.dart | 12 +-- pkgs/source_span/test/utils_test.dart | 10 +-- 16 files changed, 114 insertions(+), 141 deletions(-) create mode 100644 pkgs/source_span/.github/dependabot.yml diff --git a/pkgs/source_span/.github/dependabot.yml b/pkgs/source_span/.github/dependabot.yml new file mode 100644 index 000000000..9735d75f3 --- /dev/null +++ b/pkgs/source_span/.github/dependabot.yml @@ -0,0 +1,10 @@ +# Set update schedule for GitHub Actions +# See https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot + +version: 2 +updates: + +- package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 8c20eeb6d..bc4359926 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,8 +22,8 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@v2 - - uses: dart-lang/setup-dart@v1.0 + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d with: sdk: ${{ matrix.sdk }} - id: install @@ -47,10 +47,10 @@ jobs: matrix: # Add macos-latest and/or windows-latest if relevant for this package. os: [ubuntu-latest] - sdk: [dev] + sdk: [2.18.0, dev] steps: - - uses: actions/checkout@v2 - - uses: dart-lang/setup-dart@v1.0 + - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d with: sdk: ${{ matrix.sdk }} - id: install diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 4c4907906..05c7e71d5 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.9.2-dev + +* Require Dart 2.18 + # 1.9.1 * Properly handle multi-line labels for multi-span highlights. diff --git a/pkgs/source_span/analysis_options.yaml b/pkgs/source_span/analysis_options.yaml index 97c0552ff..8b32d108a 100644 --- a/pkgs/source_span/analysis_options.yaml +++ b/pkgs/source_span/analysis_options.yaml @@ -1,91 +1,56 @@ +# https://dart.dev/guides/language/analysis-options include: package:lints/recommended.yaml analyzer: - strong-mode: - implicit-casts: false + language: + strict-casts: true + strict-inference: true + strict-raw-types: true linter: rules: - always_declare_return_types - - annotate_overrides - avoid_bool_literals_in_conditional_expressions + - avoid_catching_errors - 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_dynamic_calls + - avoid_private_typedef_functions + - avoid_redundant_argument_values - 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 + - avoid_void_async - cancel_subscriptions - cascade_invocations - 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 - - iterable_contains_unrelated_type - - library_names - - library_prefixes - - list_remove_unrelated_type + - join_return_with_assignment + - lines_longer_than_80_chars + - literal_only_boolean_expressions + - missing_whitespace_between_adjacent_strings - 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_asserts_in_initializer_lists - prefer_const_constructors - - prefer_contains - - prefer_equal_for_default_values - - prefer_final_fields + - prefer_const_declarations + - prefer_expression_function_bodies - 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_typing_uninitialized_variables - - recursive_getters - - slash_for_doc_comments + - prefer_relative_imports + - prefer_single_quotes + - sort_pub_dependencies - test_types_in_equals - throw_in_finally - - type_init_formals + - type_annotate_public_apis - 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_raw_strings - unnecessary_statements - - unnecessary_this - - unrelated_type_equality_checks - - use_function_type_syntax_for_parameters - - use_rethrow_when_possible - - valid_regexps - - void_checks + - use_if_null_to_convert_nulls_to_bools + - use_raw_strings + - use_string_buffers + - use_super_parameters diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 473b8c17a..52d1b6cca 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -51,14 +51,14 @@ class SourceFile { /// This constructor is deprecated. /// - /// Use [new SourceFile.fromString] instead. + /// Use [SourceFile.fromString] instead. @Deprecated('Will be removed in 2.0.0') - SourceFile(String text, {url}) : this.decoded(text.runes, url: url); + SourceFile(String text, {Object? url}) : this.decoded(text.runes, url: url); /// Creates a new source file from [text]. /// /// [url] may be either a [String], a [Uri], or `null`. - SourceFile.fromString(String text, {url}) + SourceFile.fromString(String text, {Object? url}) : this.decoded(text.codeUnits, url: url); /// Creates a new source file from a list of decoded code units. @@ -70,7 +70,7 @@ class SourceFile { /// surrogate pairs. **This behavior is deprecated**. For /// forwards-compatibility, callers should only pass in characters less than /// or equal to `0xFFFF`. - SourceFile.decoded(Iterable decodedChars, {url}) + SourceFile.decoded(Iterable decodedChars, {Object? url}) : url = url is String ? Uri.parse(url) : url as Uri?, _decodedChars = Uint32List.fromList(decodedChars.toList()) { for (var i = 0; i < _decodedChars.length; i++) { @@ -387,7 +387,7 @@ class _FileSpan extends SourceSpanMixin implements FileSpan { } @override - bool operator ==(other) { + bool operator ==(Object other) { if (other is! FileSpan) return super == other; if (other is! _FileSpan) { return super == other && sourceUrl == other.sourceUrl; diff --git a/pkgs/source_span/lib/src/highlighter.dart b/pkgs/source_span/lib/src/highlighter.dart index 53f3d6377..19e04d02e 100644 --- a/pkgs/source_span/lib/src/highlighter.dart +++ b/pkgs/source_span/lib/src/highlighter.dart @@ -58,7 +58,7 @@ class Highlighter { /// should be used. /// /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors - Highlighter(SourceSpan span, {color}) + Highlighter(SourceSpan span, {Object? color}) : this._(_collateLines([_Highlight(span, primary: true)]), () { if (color == true) return colors.red; if (color == false) return null; @@ -95,13 +95,14 @@ class Highlighter { Highlighter._(this._lines, this._primaryColor, this._secondaryColor) : _paddingBeforeSidebar = 1 + math.max( - // In a purely mathematical world, floor(log10(n)) would give the - // number of digits in n, but floating point errors render that - // unreliable in practice. - (_lines.last.number + 1).toString().length, - // If [_lines] aren't contiguous, we'll write "..." in place of a - // line number. - _contiguous(_lines) ? 0 : 3), + // In a purely mathematical world, floor(log10(n)) would give the + // number of digits in n, but floating point errors render that + // unreliable in practice. + (_lines.last.number + 1).toString().length, + // If [_lines] aren't contiguous, we'll write "..." in place of a + // line number. + _contiguous(_lines) ? 0 : 3, + ), _maxMultilineSpans = _lines .map((line) => line.highlights .where((highlight) => isMultiline(highlight.span)) @@ -155,7 +156,7 @@ class Highlighter { var lineNumber = highlight.span.start.line - linesBeforeSpan; for (var line in context.split('\n')) { - // Only add a line if it hasn't already been added for a previous span. + // Only add a line if it hasn't already been added for a previous span if (lines.isEmpty || lineNumber > lines.last.number) { lines.add(_Line(line, lineNumber, url)); } @@ -192,7 +193,8 @@ class Highlighter { // Each index of this list represents a column after the sidebar that could // contain a line indicating an active highlight. If it's `null`, that - // column is empty; if it contains a highlight, it should be drawn for that column. + // column is empty; if it contains a highlight, it should be drawn for that + // column. final highlightsByColumn = List<_Highlight?>.filled(_maxMultilineSpans, null); @@ -332,7 +334,7 @@ class Highlighter { } else if (endLine == line.number && highlight.span.end.column == line.text.length) { _buffer.write(highlight.label == null - ? glyph.glyphOrAscii('└', '\\') + ? glyph.glyphOrAscii('└', r'\') : vertical); } else { _colorize(() { diff --git a/pkgs/source_span/lib/src/location.dart b/pkgs/source_span/lib/src/location.dart index 634863bf0..8f22d7ba2 100644 --- a/pkgs/source_span/lib/src/location.dart +++ b/pkgs/source_span/lib/src/location.dart @@ -42,7 +42,7 @@ class SourceLocation implements Comparable { /// means that [line] defaults to 0 and [column] defaults to [offset]. /// /// [sourceUrl] may be either a [String], a [Uri], or `null`. - SourceLocation(this.offset, {sourceUrl, int? line, int? column}) + SourceLocation(this.offset, {Object? sourceUrl, int? line, int? column}) : sourceUrl = sourceUrl is String ? Uri.parse(sourceUrl) : sourceUrl as Uri?, line = line ?? 0, @@ -83,7 +83,7 @@ class SourceLocation implements Comparable { } @override - bool operator ==(other) => + bool operator ==(Object other) => other is SourceLocation && sourceUrl == other.sourceUrl && offset == other.offset; @@ -98,6 +98,5 @@ class SourceLocation implements Comparable { /// A base class for source locations with [offset], [line], and [column] known /// at construction time. class SourceLocationBase extends SourceLocation { - SourceLocationBase(int offset, {sourceUrl, int? line, int? column}) - : super(offset, sourceUrl: sourceUrl, line: line, column: column); + SourceLocationBase(super.offset, {super.sourceUrl, super.line, super.column}); } diff --git a/pkgs/source_span/lib/src/location_mixin.dart b/pkgs/source_span/lib/src/location_mixin.dart index bae38befa..a44f5e295 100644 --- a/pkgs/source_span/lib/src/location_mixin.dart +++ b/pkgs/source_span/lib/src/location_mixin.dart @@ -42,7 +42,7 @@ abstract class SourceLocationMixin implements SourceLocation { } @override - bool operator ==(other) => + bool operator ==(Object other) => other is SourceLocation && sourceUrl == other.sourceUrl && offset == other.offset; diff --git a/pkgs/source_span/lib/src/span.dart b/pkgs/source_span/lib/src/span.dart index 05fd340a2..941dedce1 100644 --- a/pkgs/source_span/lib/src/span.dart +++ b/pkgs/source_span/lib/src/span.dart @@ -67,7 +67,7 @@ abstract class SourceSpan implements Comparable { /// characters if it's `true`. /// /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors - String message(String message, {color}); + String message(String message, {Object? color}); /// Prints the text associated with this span in a user-friendly way. /// @@ -87,7 +87,7 @@ abstract class SourceSpan implements Comparable { /// characters if it's `true`. /// /// [ANSI terminal color escape]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors - String highlight({color}); + String highlight({Object? color}); } /// A base class for source spans with [start], [end], and [text] known at diff --git a/pkgs/source_span/lib/src/span_exception.dart b/pkgs/source_span/lib/src/span_exception.dart index c6db03ba2..90ad690d3 100644 --- a/pkgs/source_span/lib/src/span_exception.dart +++ b/pkgs/source_span/lib/src/span_exception.dart @@ -28,7 +28,7 @@ class SourceSpanException implements Exception { /// 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}) { + String toString({Object? color}) { if (span == null) return message; return 'Error on ${span!.message(message, color: color)}'; } @@ -43,8 +43,7 @@ class SourceSpanFormatException extends SourceSpanException @override int? get offset => span?.start.offset; - SourceSpanFormatException(String message, SourceSpan? span, [this.source]) - : super(message, span); + SourceSpanFormatException(super.message, super.span, [this.source]); } /// A [SourceSpanException] that also highlights some secondary spans to provide @@ -64,10 +63,9 @@ class MultiSourceSpanException extends SourceSpanException { /// additional information and helps distinguish it from [secondarySpans]. final Map secondarySpans; - MultiSourceSpanException(String message, SourceSpan? span, this.primaryLabel, + MultiSourceSpanException(super.message, super.span, this.primaryLabel, Map secondarySpans) - : secondarySpans = Map.unmodifiable(secondarySpans), - super(message, span); + : secondarySpans = Map.unmodifiable(secondarySpans); /// Returns a string representation of `this`. /// @@ -80,7 +78,7 @@ class MultiSourceSpanException extends SourceSpanException { /// If [color] is `true` or a string, [secondaryColor] is used to highlight /// [secondarySpans]. @override - String toString({color, String? secondaryColor}) { + String toString({Object? color, String? secondaryColor}) { if (span == null) return message; var useColor = false; @@ -110,8 +108,7 @@ class MultiSourceSpanFormatException extends MultiSourceSpanException @override int? get offset => span?.start.offset; - MultiSourceSpanFormatException(String message, SourceSpan? span, - String primaryLabel, Map secondarySpans, - [this.source]) - : super(message, span, primaryLabel, secondarySpans); + MultiSourceSpanFormatException( + super.message, super.span, super.primaryLabel, super.secondarySpans, + [this.source]); } diff --git a/pkgs/source_span/lib/src/span_mixin.dart b/pkgs/source_span/lib/src/span_mixin.dart index 4d7bab473..29b6119d2 100644 --- a/pkgs/source_span/lib/src/span_mixin.dart +++ b/pkgs/source_span/lib/src/span_mixin.dart @@ -50,7 +50,7 @@ abstract class SourceSpanMixin implements SourceSpan { } @override - String message(String message, {color}) { + String message(String message, {Object? color}) { final buffer = StringBuffer() ..write('line ${start.line + 1}, column ${start.column + 1}'); if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}'); @@ -67,13 +67,13 @@ abstract class SourceSpanMixin implements SourceSpan { } @override - String highlight({color}) { + String highlight({Object? color}) { if (this is! SourceSpanWithContext && length == 0) return ''; return Highlighter(this, color: color).highlight(); } @override - bool operator ==(other) => + bool operator ==(Object other) => other is SourceSpan && start == other.start && end == other.end; @override diff --git a/pkgs/source_span/lib/src/utils.dart b/pkgs/source_span/lib/src/utils.dart index 7df0bafca..aba14ecf9 100644 --- a/pkgs/source_span/lib/src/utils.dart +++ b/pkgs/source_span/lib/src/utils.dart @@ -9,12 +9,12 @@ import 'span_with_context.dart'; /// Returns the minimum of [obj1] and [obj2] according to /// [Comparable.compareTo]. -T min(T obj1, T obj2) => +T min>(T obj1, T obj2) => obj1.compareTo(obj2) > 0 ? obj2 : obj1; /// Returns the maximum of [obj1] and [obj2] according to /// [Comparable.compareTo]. -T max(T obj1, T obj2) => +T max>(T obj1, T obj2) => obj1.compareTo(obj2) > 0 ? obj1 : obj2; /// Returns whether all elements of [iter] are the same value, according to diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 8bde1c281..4531a74e3 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,10 +1,10 @@ name: source_span -version: 1.9.1 +version: 1.9.2-dev description: A library for identifying source spans and locations. repository: https://github.com/dart-lang/source_span environment: - sdk: ">=2.14.0 <3.0.0" + sdk: ">=2.18.0 <3.0.0" dependencies: collection: ^1.15.0 @@ -12,5 +12,5 @@ dependencies: term_glyph: ^1.2.0 dev_dependencies: - lints: ^1.0.0 + lints: ^2.0.0 test: ^1.16.0 diff --git a/pkgs/source_span/test/highlight_test.dart b/pkgs/source_span/test/highlight_test.dart index 7754d0076..93c42dbaa 100644 --- a/pkgs/source_span/test/highlight_test.dart +++ b/pkgs/source_span/test/highlight_test.dart @@ -232,28 +232,28 @@ foo bar '''); - expect(file.span(4, 9).highlight(), equals(""" + expect(file.span(4, 9).highlight(), equals(r""" , 2 | / -3 | \\ bar +3 | \ bar '""")); }); test('highlights the full last line', () { - expect(file.span(4, 27).highlight(), equals(""" + expect(file.span(4, 27).highlight(), equals(r""" , 1 | foo bar baz | ,-----^ -2 | \\ whiz bang boom +2 | \ whiz bang boom '""")); }); test('highlights the full last line with no trailing newline', () { - expect(file.span(4, 26).highlight(), equals(""" + expect(file.span(4, 26).highlight(), equals(r""" , 1 | foo bar baz | ,-----^ -2 | \\ whiz bang boom +2 | \ whiz bang boom '""")); }); @@ -264,21 +264,21 @@ whiz bang boom\r zip zap zop\r '''); - expect(file.span(4, 29).highlight(), equals(""" + expect(file.span(4, 29).highlight(), equals(r""" , 1 | foo bar baz | ,-----^ -2 | \\ whiz bang boom +2 | \ whiz bang boom '""")); }); test('highlights the full last line at the end of the file', () { - expect(file.span(4, 39).highlight(), equals(""" + expect(file.span(4, 39).highlight(), equals(r""" , 1 | foo bar baz | ,-----^ 2 | | whiz bang boom -3 | \\ zip zap zop +3 | \ zip zap zop '""")); }); @@ -290,12 +290,12 @@ foo bar baz whiz bang boom zip zap zop'''); - expect(file.span(4, 38).highlight(), equals(""" + expect(file.span(4, 38).highlight(), equals(r""" , 1 | foo bar baz | ,-----^ 2 | | whiz bang boom -3 | \\ zip zap zop +3 | \ zip zap zop '""")); }); @@ -306,31 +306,31 @@ foo bar '''); - expect(file.span(0, 5).highlight(), equals(""" + expect(file.span(0, 5).highlight(), equals(r""" , 1 | / foo -2 | \\ +2 | \ '""")); }); test('highlights multiple empty lines', () { final file = SourceFile.fromString('foo\n\n\n\nbar'); - expect(file.span(4, 7).highlight(), equals(""" + expect(file.span(4, 7).highlight(), equals(r""" , 2 | / 3 | | -4 | \\ +4 | \ '""")); }); // Regression test for #32 test('highlights the end of a line and an empty line', () { final file = SourceFile.fromString('foo\n\n'); - expect(file.span(3, 5).highlight(), equals(""" + expect(file.span(3, 5).highlight(), equals(r""" , 1 | foo | ,----^ -2 | \\ +2 | \ '""")); }); }); @@ -520,12 +520,12 @@ whiz bang\tboom 'foo\nbar\n', 'previous\nlines\nfoo\nbar\nfollowing line\n'); - expect(span.highlight(), equals(""" + expect(span.highlight(), equals(r""" , 1 | previous 2 | lines 3 | / foo -4 | \\ bar +4 | \ bar 5 | following line '""")); }); diff --git a/pkgs/source_span/test/multiple_highlight_test.dart b/pkgs/source_span/test/multiple_highlight_test.dart index ba4d686b3..139d53c8a 100644 --- a/pkgs/source_span/test/multiple_highlight_test.dart +++ b/pkgs/source_span/test/multiple_highlight_test.dart @@ -280,8 +280,7 @@ quibble bibble boop }); test('allows secondary spans to have null URL', () { - final span2 = SourceSpan(SourceLocation(1, sourceUrl: null), - SourceLocation(4, sourceUrl: null), 'foo'); + final span2 = SourceSpan(SourceLocation(1), SourceLocation(4), 'foo'); expect( file.span(31, 34).highlightMultiple('one', {span2: 'two'}), equals(""" @@ -296,8 +295,7 @@ quibble bibble boop }); test('allows primary span to have null URL', () { - final span1 = SourceSpan(SourceLocation(1, sourceUrl: null), - SourceLocation(4, sourceUrl: null), 'foo'); + final span1 = SourceSpan(SourceLocation(1), SourceLocation(4), 'foo'); expect( span1.highlightMultiple('one', {file.span(31, 34): 'two'}), equals(""" @@ -313,10 +311,8 @@ quibble bibble boop }); test('highlights multiple null URLs as separate files', () { - final span1 = SourceSpan(SourceLocation(1, sourceUrl: null), - SourceLocation(4, sourceUrl: null), 'foo'); - final span2 = SourceSpan(SourceLocation(1, sourceUrl: null), - SourceLocation(4, sourceUrl: null), 'bar'); + final span1 = SourceSpan(SourceLocation(1), SourceLocation(4), 'foo'); + final span2 = SourceSpan(SourceLocation(1), SourceLocation(4), 'bar'); expect(span1.highlightMultiple('one', {span2: 'two'}), equals(""" , diff --git a/pkgs/source_span/test/utils_test.dart b/pkgs/source_span/test/utils_test.dart index 293b30023..91397c01b 100644 --- a/pkgs/source_span/test/utils_test.dart +++ b/pkgs/source_span/test/utils_test.dart @@ -8,14 +8,14 @@ import 'package:test/test.dart'; void main() { group('find line start', () { test('skip entries in wrong column', () { - final context = '0_bb\n1_bbb\n2b____\n3bbb\n'; + const 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', () { - final context = '0123\n56789\nabcdefgh\n'; + const context = '0123\n56789\nabcdefgh\n'; final index = findLineStart(context, '', 5)!; expect(index, 5); expect(context[index], '5'); @@ -38,19 +38,19 @@ void main() { }); test('found on the first line', () { - final context = '0\n2\n45\n'; + const context = '0\n2\n45\n'; final index = findLineStart(context, '0', 0); expect(index, 0); }); test('finds text that starts with a newline', () { - final context = '0\n2\n45\n'; + const context = '0\n2\n45\n'; final index = findLineStart(context, '\n2', 1); expect(index, 0); }); test('not found', () { - final context = '0\n2\n45\n'; + const context = '0\n2\n45\n'; final index = findLineStart(context, '0', 1); expect(index, isNull); }); From ded49cfc531047109f3325174336bb4fd1006ead Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Jan 2023 10:12:07 -0800 Subject: [PATCH 097/128] Bump actions/checkout from 3.1.0 to 3.2.0 (dart-lang/source_span#89) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.1.0 to 3.2.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8...755da8c3cf115ac066823e79a1e1788f8940201b) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index bc4359926..cc5abcf3c 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [2.18.0, dev] steps: - - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d with: sdk: ${{ matrix.sdk }} From b32781391362dffd3b579430eff85ab91695cea6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Feb 2023 09:06:20 -0800 Subject: [PATCH 098/128] Bump dart-lang/setup-dart from 1.3 to 1.4 (dart-lang/source_span#91) Bumps [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart) from 1.3 to 1.4. - [Release notes](https://github.com/dart-lang/setup-dart/releases) - [Changelog](https://github.com/dart-lang/setup-dart/blob/main/CHANGELOG.md) - [Commits](https://github.com/dart-lang/setup-dart/compare/6a218f2413a3e78e9087f638a238f6b40893203d...a57a6c04cf7d4840e88432aad6281d1e125f0d46) --- updated-dependencies: - dependency-name: dart-lang/setup-dart dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index cc5abcf3c..6e0c5d097 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b - - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d + - uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46 with: sdk: ${{ matrix.sdk }} - id: install @@ -50,7 +50,7 @@ jobs: sdk: [2.18.0, dev] steps: - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b - - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d + - uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46 with: sdk: ${{ matrix.sdk }} - id: install From 8a9307efbe99d311e94e446ddd69dff16c7667e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Feb 2023 09:13:43 -0800 Subject: [PATCH 099/128] Bump actions/checkout from 3.2.0 to 3.3.0 (dart-lang/source_span#90) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.2.0 to 3.3.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/755da8c3cf115ac066823e79a1e1788f8940201b...ac593985615ec2ede58e132d2e21d2b1cbd6127c) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 6e0c5d097..5a03db3b3 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c - uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46 with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [2.18.0, dev] steps: - - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c - uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46 with: sdk: ${{ matrix.sdk }} From 5499677013783d5499f8c73faebf7a4cf76ec230 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Fri, 3 Feb 2023 12:15:20 -0800 Subject: [PATCH 100/128] add an api usage example (dart-lang/source_span#92) * add an api usage example * Apply suggestions from code review Co-authored-by: Kevin Moore * make method private --------- Co-authored-by: Kevin Moore --- pkgs/source_span/CHANGELOG.md | 3 +- pkgs/source_span/README.md | 2 ++ pkgs/source_span/example/main.dart | 51 ++++++++++++++++++++++++++++++ pkgs/source_span/pubspec.yaml | 3 +- 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 pkgs/source_span/example/main.dart diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 05c7e71d5..fa1735aa2 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,6 +1,7 @@ # 1.9.2-dev * Require Dart 2.18 +* Add an API usage example in `example/`. # 1.9.1 @@ -201,7 +202,7 @@ # 1.0.0 This package was extracted from the -[`source_maps`](http://pub.dartlang.org/packages/source_maps) package, but the +[`source_maps`](https://pub.dev/packages/source_maps) package, but the API has many differences. Among them: * `Span` has been renamed to `SourceSpan` and `Location` has been renamed to diff --git a/pkgs/source_span/README.md b/pkgs/source_span/README.md index be91debd0..0faf0cbc4 100644 --- a/pkgs/source_span/README.md +++ b/pkgs/source_span/README.md @@ -2,6 +2,8 @@ [![pub package](https://img.shields.io/pub/v/source_span.svg)](https://pub.dev/packages/source_span) [![package publisher](https://img.shields.io/pub/publisher/source_span.svg)](https://pub.dev/packages/source_span/publisher) +## About this package + `source_span` is a library for tracking locations in source code. It's designed to provide a standard representation for source code locations and spans so that disparate packages can easily pass them among one another, and to make it easy diff --git a/pkgs/source_span/example/main.dart b/pkgs/source_span/example/main.dart new file mode 100644 index 000000000..e29676590 --- /dev/null +++ b/pkgs/source_span/example/main.dart @@ -0,0 +1,51 @@ +// Copyright (c) 2023, 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 'dart:io'; + +import 'package:source_span/source_span.dart'; + +void main(List args) { + final file = File('README.md'); + final contents = file.readAsStringSync(); + + final sourceFile = SourceFile.fromString(contents, url: file.uri); + final spans = _parseFile(contents, sourceFile); + + for (var span in spans.take(30)) { + print('[${span.start.line + 1}:${span.start.column + 1}] ${span.text}'); + } +} + +Iterable _parseFile(String contents, SourceFile sourceFile) sync* { + var wordStart = 0; + var inWhiteSpace = true; + + for (var i = 0; i < contents.length; i++) { + final codeUnit = contents.codeUnitAt(i); + + if (codeUnit == _eol || codeUnit == _space) { + if (!inWhiteSpace) { + inWhiteSpace = true; + + // emit a word + yield sourceFile.span(wordStart, i); + } + } else { + if (inWhiteSpace) { + inWhiteSpace = false; + + wordStart = i; + } + } + } + + if (!inWhiteSpace) { + // emit a word + yield sourceFile.span(wordStart, contents.length); + } +} + +const int _eol = 10; +const int _space = 32; diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 4531a74e3..d00730c39 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,6 +1,7 @@ name: source_span version: 1.9.2-dev -description: A library for identifying source spans and locations. +description: >- + Provides a standard representation for source code locations and spans. repository: https://github.com/dart-lang/source_span environment: From 7a2837b681011a6165b233c1f2f13c1359cdf700 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 15:32:56 -0700 Subject: [PATCH 101/128] Bump dart-lang/setup-dart from 1.4.0 to 1.5.0 (dart-lang/source_span#95) Bumps [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart) from 1.4.0 to 1.5.0. - [Release notes](https://github.com/dart-lang/setup-dart/releases) - [Changelog](https://github.com/dart-lang/setup-dart/blob/main/CHANGELOG.md) - [Commits](https://github.com/dart-lang/setup-dart/compare/a57a6c04cf7d4840e88432aad6281d1e125f0d46...d6a63dab3335f427404425de0fbfed4686d93c4f) --- updated-dependencies: - dependency-name: dart-lang/setup-dart dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 5a03db3b3..2874adcba 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c - - uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46 + - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} - id: install @@ -50,7 +50,7 @@ jobs: sdk: [2.18.0, dev] steps: - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c - - uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46 + - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} - id: install From dab9e4e893addf9323873f1b4fcc769a617624e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 15:36:58 -0700 Subject: [PATCH 102/128] Bump actions/checkout from 3.3.0 to 3.5.0 (dart-lang/source_span#94) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.3.0 to 3.5.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/ac593985615ec2ede58e132d2e21d2b1cbd6127c...8f4b7f84864484a7bf31766abe9204da3cbe65b3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 2874adcba..b70103cd7 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c + - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [2.18.0, dev] steps: - - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c + - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} From dd5ecf129c04901bd81fc0b1a076cd0aad889c37 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Wed, 5 Apr 2023 15:28:04 -0700 Subject: [PATCH 103/128] blast_repo fixes (dart-lang/source_span#96) * blast_repo fixes auto-publish * update changelog --- .../.github/workflows/publish.yaml | 14 ++++ pkgs/source_span/CHANGELOG.md | 70 +++++++++---------- 2 files changed, 49 insertions(+), 35 deletions(-) create mode 100644 pkgs/source_span/.github/workflows/publish.yaml diff --git a/pkgs/source_span/.github/workflows/publish.yaml b/pkgs/source_span/.github/workflows/publish.yaml new file mode 100644 index 000000000..2239b63d3 --- /dev/null +++ b/pkgs/source_span/.github/workflows/publish.yaml @@ -0,0 +1,14 @@ +# A CI configuration to auto-publish pub packages. + +name: Publish + +on: + pull_request: + branches: [ master ] + push: + tags: [ 'v[0-9]+.[0-9]+.[0-9]+' ] + +jobs: + publish: + if: ${{ github.repository_owner == 'dart-lang' }} + uses: dart-lang/ecosystem/.github/workflows/publish.yaml@main diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index fa1735aa2..f69f0b872 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,40 +1,40 @@ -# 1.9.2-dev +## 1.9.2-dev * Require Dart 2.18 * Add an API usage example in `example/`. -# 1.9.1 +## 1.9.1 * Properly handle multi-line labels for multi-span highlights. * Populate the pubspec `repository` field. -# 1.9.0 +## 1.9.0 * Add `SourceSpanWithContextExtension.subspan` that returns a `SourceSpanWithContext` rather than a plain `SourceSpan`. -# 1.8.2 +## 1.8.2 * Fix a bug where highlighting multiple spans with `null` URLs could cause an assertion error. Now when multiple spans are passed with `null` URLs, they're highlighted as though they all come from different source files. -# 1.8.1 +## 1.8.1 * Fix a bug where the URL header for the highlights with multiple files would get omitted only one span has a non-null URI. -# 1.8.0 +## 1.8.0 * Stable release for null safety. -# 1.7.0 +## 1.7.0 * Add a `SourceSpan.subspan()` extension method which returns a slice of an existing source span. -# 1.6.0 +## 1.6.0 * Add support for highlighting multiple source spans at once, providing more context for span-based messages. This is exposed through the new APIs @@ -42,28 +42,28 @@ extension methods), `MultiSourceSpanException`, and `MultiSourceSpanFormatException`. -# 1.5.6 +## 1.5.6 * Fix padding around line numbers that are powers of 10 in `FileSpan.highlight()`. -# 1.5.5 +## 1.5.5 * Fix a bug where `FileSpan.highlight()` would crash for spans that covered a trailing newline and a single additional empty line. -# 1.5.4 +## 1.5.4 * `FileSpan.highlight()` now properly highlights point spans at the beginning of lines. -# 1.5.3 +## 1.5.3 * Fix an edge case where `FileSpan.highlight()` would put the highlight indicator in the wrong position when highlighting a point span after the end of a file. -# 1.5.2 +## 1.5.2 * `SourceFile.span()` now goes to the end of the file by default, rather than ending one character before the end of the file. This matches the documented @@ -75,7 +75,7 @@ * Fix an edge case where `FileSpan.highlight()` could crash when highlighting a span that ended with an empty line. -# 1.5.1 +## 1.5.1 * Produce better source span highlights for multi-line spans that cover the entire last line of the span, including the newline. @@ -83,7 +83,7 @@ * Produce better source span highlights for spans that contain Windows-style newlines. -# 1.5.0 +## 1.5.0 * Improve the output of `SourceSpan.highlight()` and `SourceSpan.message()`: @@ -94,11 +94,11 @@ [`term_glyph.ascii`]: https://pub.dartlang.org/documentation/term_glyph/latest/term_glyph/ascii.html -# 1.4.1 +## 1.4.1 * Set max SDK version to `<3.0.0`, and adjust other dependencies. -# 1.4.0 +## 1.4.0 * The `new SourceFile()` constructor is deprecated. This constructed a source file from a string's runes, rather than its code units, which runs counter to @@ -111,36 +111,36 @@ * The current behavior when characters larger than `0xFFFF` are passed to `new SourceFile.decoded()` is now considered deprecated. -# 1.3.1 +## 1.3.1 * Properly highlight spans for lines that include tabs with `SourceSpan.highlight()` and `SourceSpan.message()`. -# 1.3.0 +## 1.3.0 * Add `SourceSpan.highlight()`, which returns just the highlighted text that would be included in `SourceSpan.message()`. -# 1.2.4 +## 1.2.4 * Fix a new strong mode error. -# 1.2.3 +## 1.2.3 * Fix a bug where a point span at the end of a file without a trailing newline would be printed incorrectly. -# 1.2.2 +## 1.2.2 * Allow `SourceSpanException.message`, `SourceSpanFormatException.source`, and `SourceSpanWithContext.context` to be overridden in strong mode. -# 1.2.1 +## 1.2.1 * Fix the declared type of `FileSpan.start` and `FileSpan.end`. In 1.2.0 these were mistakenly changed from `FileLocation` to `SourceLocation`. -# 1.2.0 +## 1.2.0 * **Deprecated:** Extending `SourceLocation` directly is deprecated. Instead, extend the new `SourceLocationBase` class or mix in the new @@ -148,58 +148,58 @@ * Dramatically improve the performance of `FileLocation`. -# 1.1.6 +## 1.1.6 * Optimize `getLine()` in `SourceFile` when repeatedly called. -# 1.1.5 +## 1.1.5 * Fixed another case in which `FileSpan.union` could throw an exception for external implementations of `FileSpan`. -# 1.1.4 +## 1.1.4 * Eliminated dart2js warning about overriding `==`, but not `hashCode`. -# 1.1.3 +## 1.1.3 * `FileSpan.compareTo`, `FileSpan.==`, `FileSpan.union`, and `FileSpan.expand` no longer throw exceptions for external implementations of `FileSpan`. * `FileSpan.hashCode` now fully agrees with `FileSpan.==`. -# 1.1.2 +## 1.1.2 * Fixed validation in `SourceSpanWithContext` to allow multiple occurrences of `text` within `context`. -# 1.1.1 +## 1.1.1 * Fixed `FileSpan`'s context to include the full span text, not just the first line of it. -# 1.1.0 +## 1.1.0 * Added `SourceSpanWithContext`: a span that also includes the full line of text that contains the span. -# 1.0.3 +## 1.0.3 * Cleanup equality operator to accept any Object rather than just a `SourceLocation`. -# 1.0.2 +## 1.0.2 * Avoid unintentionally allocating extra objects for internal `FileSpan` operations. * Ensure that `SourceSpan.operator==` works on arbitrary `Object`s. -# 1.0.1 +## 1.0.1 * Use a more compact internal representation for `FileSpan`. -# 1.0.0 +## 1.0.0 This package was extracted from the [`source_maps`](https://pub.dev/packages/source_maps) package, but the From 0c19dae62cfc724eb020ce7ba087c266d790efda Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 5 Apr 2023 16:52:39 -0700 Subject: [PATCH 104/128] Add public access to a SourceFile's code units (dart-lang/source_span#93) * Add public access to a SourceFile's code units This makes it possible to efficiently reparse information from around a `FileSpan`, such as to expand it through surrounding whitespace characters. Otherwise, a caller would have to call `getText()` which can be very expensive in a tight loop. * Fix lints * Update CHANGELOG.md Co-authored-by: Devon Carew --------- Co-authored-by: Devon Carew --- pkgs/source_span/CHANGELOG.md | 3 ++- pkgs/source_span/lib/src/file.dart | 10 +++++++++- pkgs/source_span/pubspec.yaml | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index f69f0b872..17812f6f6 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,5 +1,6 @@ -## 1.9.2-dev +## 1.10.0 +* Add a `SourceFile.codeUnits` property. * Require Dart 2.18 * Add an API usage example in `example/`. diff --git a/pkgs/source_span/lib/src/file.dart b/pkgs/source_span/lib/src/file.dart index 52d1b6cca..74c923459 100644 --- a/pkgs/source_span/lib/src/file.dart +++ b/pkgs/source_span/lib/src/file.dart @@ -32,7 +32,15 @@ class SourceFile { /// the file. final _lineStarts = [0]; - /// The code points of the characters in the file. + /// The code units of the characters in the file. + /// + /// If this was constructed with the deprecated `SourceFile()` constructor, + /// this will instead contain the code _points_ of the characters in the file + /// (so characters above 2^16 are represented as individual integers rather + /// than surrogate pairs). + List get codeUnits => _decodedChars; + + /// The code units of the characters in this file. final Uint32List _decodedChars; /// The length of the file in characters. diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index d00730c39..44156ee5a 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.9.2-dev +version: 1.10.0 description: >- Provides a standard representation for source code locations and spans. repository: https://github.com/dart-lang/source_span From 5eaf67b999ffcc0cf588b79590e46185ece2ecf5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 May 2023 11:12:49 -0700 Subject: [PATCH 105/128] Bump actions/checkout from 3.5.0 to 3.5.2 (dart-lang/source_span#97) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.0 to 3.5.2. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/8f4b7f84864484a7bf31766abe9204da3cbe65b3...8e5e7e5ab8b370d6c329ec480221332ada57f0ab) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index b70103cd7..2d36a3b10 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [2.18.0, dev] steps: - - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} From 5ea8221d905037ea059695ce534915e54bba8c7e Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Tue, 23 May 2023 10:10:17 -0700 Subject: [PATCH 106/128] blast_repo fixes (dart-lang/source_span#98) dependabot --- pkgs/source_span/.github/dependabot.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pkgs/source_span/.github/dependabot.yml b/pkgs/source_span/.github/dependabot.yml index 9735d75f3..c6531d433 100644 --- a/pkgs/source_span/.github/dependabot.yml +++ b/pkgs/source_span/.github/dependabot.yml @@ -4,7 +4,9 @@ version: 2 updates: -- package-ecosystem: "github-actions" - directory: "/" +- package-ecosystem: github-actions + directory: / schedule: - interval: "monthly" + interval: monthly + labels: + - autosubmit From 79b03a999edf9e76f8b32ad9702ebf6564c38889 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jul 2023 17:25:29 +0000 Subject: [PATCH 107/128] Bump actions/checkout from 3.5.2 to 3.5.3 (dart-lang/source_span#99) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.2 to 3.5.3.
Release notes

Sourced from actions/checkout's releases.

v3.5.3

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v3...v3.5.3

Changelog

Sourced from actions/checkout's changelog.

Changelog

v3.5.3

v3.5.2

v3.5.1

v3.5.0

v3.4.0

v3.3.0

v3.2.0

v3.1.0

v3.0.2

v3.0.1

v3.0.0

v2.3.1

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=3.5.2&new-version=3.5.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 2d36a3b10..7e593e5ce 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [2.18.0, dev] steps: - - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} From b773a934097f156a2ef46718bbfcc40f15feeabf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 17:25:56 +0000 Subject: [PATCH 108/128] Bump actions/checkout from 3.5.3 to 3.6.0 (dart-lang/source_span#101) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.3 to 3.6.0.
Release notes

Sourced from actions/checkout's releases.

v3.6.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v3.5.3...v3.6.0

Changelog

Sourced from actions/checkout's changelog.

Changelog

v3.6.0

v3.5.3

v3.5.2

v3.5.1

v3.5.0

v3.4.0

v3.3.0

v3.2.0

v3.1.0

v3.0.2

v3.0.1

v3.0.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=3.5.3&new-version=3.6.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 7e593e5ce..3c54fc1b7 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [2.18.0, dev] steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f with: sdk: ${{ matrix.sdk }} From 916d92d5dc5290e1a1434a6b75ebbfc167c199dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 18:02:11 +0000 Subject: [PATCH 109/128] Bump dart-lang/setup-dart from 1.5.0 to 1.5.1 (dart-lang/source_span#103) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart) from 1.5.0 to 1.5.1.
Release notes

Sourced from dart-lang/setup-dart's releases.

v1.5.1

  • No longer test the setup-dart action on pre-2.12 SDKs.
  • Upgrade JS interop code to use extension types (the new name for inline classes).
  • The upcoming rename of the be channel to main is now supported with forward compatibility that switches when the rename happens.
Changelog

Sourced from dart-lang/setup-dart's changelog.

v1.6.0

  • Enable provisioning of the latest Dart SDK patch release by specifying just the major and minor version (e.g. 3.2).

v1.5.1

  • No longer test the setup-dart action on pre-2.12 SDKs.
  • Upgrade JS interop code to use extension types (the new name for inline classes).
  • The upcoming rename of the be channel to main is now supported with forward compatibility that switches when the rename happens.

v1.5.0

  • Re-wrote the implementation of the action into Dart.
  • Auto-detect the platform architecture (x64, ia32, arm, arm64).
  • Improved the caching and download resilience of the sdk.
  • Added a new action output: dart-version - the installed version of the sdk.

v1.4.0

  • Automatically create OIDC token for pub.dev.
  • Add a reusable workflow for publishing.

v1.3.0

v1.2.0

  • Fixed a path issue impacting git dependencies on Windows.

v1.1.0

  • Added a flavor option setup.sh to allow downloading unpublished builds.

v1.0.0

  • Promoted to 1.0 stable.

v0.5

  • Fixed a Windows pub global activate path issue.

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dart-lang/setup-dart&package-manager=github_actions&previous-version=1.5.0&new-version=1.5.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 3c54fc1b7..fe375c613 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f + - uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1 with: sdk: ${{ matrix.sdk }} - id: install @@ -50,7 +50,7 @@ jobs: sdk: [2.18.0, dev] steps: - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f + - uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1 with: sdk: ${{ matrix.sdk }} - id: install From fb8a8325791529d7c428459f63cebb75a96bb9b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 18:07:05 +0000 Subject: [PATCH 110/128] Bump actions/checkout from 3.6.0 to 4.1.0 (dart-lang/source_span#102) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 3.6.0 to 4.1.0.
Release notes

Sourced from actions/checkout's releases.

v4.1.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4.0.0...v4.1.0

v4.0.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v3...v4.0.0

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.1.0

v4.0.0

v3.6.0

v3.5.3

v3.5.2

v3.5.1

v3.5.0

v3.4.0

v3.3.0

v3.2.0

v3.1.0

v3.0.2

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=3.6.0&new-version=4.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index fe375c613..4d307f3f5 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 - uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1 with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [2.18.0, dev] steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 - uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1 with: sdk: ${{ matrix.sdk }} From 2f31c0f291f365b03b27a0559446e4e4d8faf58f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Nov 2023 17:32:29 +0000 Subject: [PATCH 111/128] Bump dart-lang/setup-dart from 1.5.1 to 1.6.0 (dart-lang/source_span#104) Bumps [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart) from 1.5.1 to 1.6.0.
Release notes

Sourced from dart-lang/setup-dart's releases.

v1.6.0

  • Enable provisioning of the latest Dart SDK patch release by specifying just the major and minor version (e.g. 3.2).
Changelog

Sourced from dart-lang/setup-dart's changelog.

v1.6.0

  • Enable provisioning of the latest Dart SDK patch release by specifying just the major and minor version (e.g. 3.2).

v1.5.1

  • No longer test the setup-dart action on pre-2.12 SDKs.
  • Upgrade JS interop code to use extension types (the new name for inline classes).
  • The upcoming rename of the be channel to main is now supported with forward compatibility that switches when the rename happens.

v1.5.0

  • Re-wrote the implementation of the action into Dart.
  • Auto-detect the platform architecture (x64, ia32, arm, arm64).
  • Improved the caching and download resilience of the sdk.
  • Added a new action output: dart-version - the installed version of the sdk.

v1.4.0

  • Automatically create OIDC token for pub.dev.
  • Add a reusable workflow for publishing.

v1.3.0

v1.2.0

  • Fixed a path issue impacting git dependencies on Windows.

v1.1.0

  • Added a flavor option setup.sh to allow downloading unpublished builds.

v1.0.0

  • Promoted to 1.0 stable.

v0.5

  • Fixed a Windows pub global activate path issue.

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dart-lang/setup-dart&package-manager=github_actions&previous-version=1.5.1&new-version=1.6.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 4d307f3f5..dda97e4da 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 - - uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1 + - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d with: sdk: ${{ matrix.sdk }} - id: install @@ -50,7 +50,7 @@ jobs: sdk: [2.18.0, dev] steps: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 - - uses: dart-lang/setup-dart@8a4b97ea2017cc079571daec46542f76189836b1 + - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d with: sdk: ${{ matrix.sdk }} - id: install From 329aec4ed899c5cbe35e6a668889bbbdea801c1e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Nov 2023 17:55:53 +0000 Subject: [PATCH 112/128] Bump actions/checkout from 4.1.0 to 4.1.1 (dart-lang/source_span#105) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.0 to 4.1.1.
Release notes

Sourced from actions/checkout's releases.

v4.1.1

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4.1.0...v4.1.1

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.1.0&new-version=4.1.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index dda97e4da..6878c5c55 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [2.18.0, dev] steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d with: sdk: ${{ matrix.sdk }} From c6f2c0e3a3f7ff01d6f73b55f3a80b4b34341901 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 29 Nov 2023 10:23:56 -0800 Subject: [PATCH 113/128] Move to latest lints, require Dart 3.1 (dart-lang/source_span#106) --- .../.github/workflows/test-package.yml | 2 +- pkgs/source_span/CHANGELOG.md | 4 +++ pkgs/source_span/analysis_options.yaml | 25 +------------------ pkgs/source_span/pubspec.yaml | 6 ++--- 4 files changed, 9 insertions(+), 28 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 6878c5c55..77ba45b39 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -47,7 +47,7 @@ jobs: matrix: # Add macos-latest and/or windows-latest if relevant for this package. os: [ubuntu-latest] - sdk: [2.18.0, dev] + sdk: [3.1.0, dev] steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index 17812f6f6..f46c1614b 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.10.1-wip + +* Require Dart 3.1 + ## 1.10.0 * Add a `SourceFile.codeUnits` property. diff --git a/pkgs/source_span/analysis_options.yaml b/pkgs/source_span/analysis_options.yaml index 8b32d108a..ae73fa5e9 100644 --- a/pkgs/source_span/analysis_options.yaml +++ b/pkgs/source_span/analysis_options.yaml @@ -1,5 +1,5 @@ # https://dart.dev/guides/language/analysis-options -include: package:lints/recommended.yaml +include: package:dart_flutter_team_lints/analysis_options.yaml analyzer: language: @@ -9,48 +9,25 @@ analyzer: linter: rules: - - always_declare_return_types - avoid_bool_literals_in_conditional_expressions - - avoid_catching_errors - avoid_classes_with_only_static_members - - avoid_dynamic_calls - avoid_private_typedef_functions - avoid_redundant_argument_values - - avoid_returning_null - - avoid_returning_null_for_future - avoid_returning_this - avoid_unused_constructor_parameters - avoid_void_async - cancel_subscriptions - cascade_invocations - - comment_references - - directives_ordering - join_return_with_assignment - - lines_longer_than_80_chars - literal_only_boolean_expressions - missing_whitespace_between_adjacent_strings - no_adjacent_strings_in_list - - omit_local_variable_types - - only_throw_errors - package_api_docs - - prefer_asserts_in_initializer_lists - - prefer_const_constructors - prefer_const_declarations - prefer_expression_function_bodies - prefer_final_locals - - prefer_relative_imports - - prefer_single_quotes - - sort_pub_dependencies - - test_types_in_equals - - throw_in_finally - - type_annotate_public_apis - - unawaited_futures - unnecessary_await_in_return - - unnecessary_lambdas - - unnecessary_parenthesis - unnecessary_raw_strings - - unnecessary_statements - use_if_null_to_convert_nulls_to_bools - use_raw_strings - use_string_buffers - - use_super_parameters diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 44156ee5a..45804e781 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,11 +1,11 @@ name: source_span -version: 1.10.0 +version: 1.10.1-wip description: >- Provides a standard representation for source code locations and spans. repository: https://github.com/dart-lang/source_span environment: - sdk: ">=2.18.0 <3.0.0" + sdk: ^3.1.0 dependencies: collection: ^1.15.0 @@ -13,5 +13,5 @@ dependencies: term_glyph: ^1.2.0 dev_dependencies: - lints: ^2.0.0 + dart_flutter_team_lints: ^2.0.0 test: ^1.16.0 From 035d7abf765c68e88ac9263304d687aeb27beb0d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Feb 2024 17:25:16 +0000 Subject: [PATCH 114/128] Bump dart-lang/setup-dart from 1.6.0 to 1.6.2 (dart-lang/source_span#107) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart) from 1.6.0 to 1.6.2.
Release notes

Sourced from dart-lang/setup-dart's releases.

v1.6.2

v1.6.1

  • Updated the google storage url for main channel releases.
Changelog

Sourced from dart-lang/setup-dart's changelog.

v1.6.2

v1.6.1

  • Updated the google storage url for main channel releases.

v1.6.0

  • Enable provisioning of the latest Dart SDK patch release by specifying just the major and minor version (e.g. 3.2).

v1.5.1

  • No longer test the setup-dart action on pre-2.12 SDKs.
  • Upgrade JS interop code to use extension types (the new name for inline classes).
  • The upcoming rename of the be channel to main is now supported with forward compatibility that switches when the rename happens.

v1.5.0

  • Re-wrote the implementation of the action into Dart.
  • Auto-detect the platform architecture (x64, ia32, arm, arm64).
  • Improved the caching and download resilience of the sdk.
  • Added a new action output: dart-version - the installed version of the sdk.

v1.4.0

  • Automatically create OIDC token for pub.dev.
  • Add a reusable workflow for publishing.

v1.3.0

v1.2.0

  • Fixed a path issue impacting git dependencies on Windows.

v1.1.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dart-lang/setup-dart&package-manager=github_actions&previous-version=1.6.0&new-version=1.6.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 77ba45b39..b98d276c3 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d + - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 with: sdk: ${{ matrix.sdk }} - id: install @@ -50,7 +50,7 @@ jobs: sdk: [3.1.0, dev] steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d + - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 with: sdk: ${{ matrix.sdk }} - id: install From 72bd3fb9f7849f42211742a962520092c0eca050 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 17:17:50 +0000 Subject: [PATCH 115/128] Bump actions/checkout from 4.1.1 to 4.1.2 (dart-lang/source_span#108) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.1 to 4.1.2.
Release notes

Sourced from actions/checkout's releases.

v4.1.2

We are investigating the following issue with this release and have rolled-back the v4 tag to point to v4.1.1

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4.1.1...v4.1.2

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.1.2

v4.1.1

v4.1.0

v4.0.0

v3.6.0

v3.5.3

v3.5.2

v3.5.1

v3.5.0

v3.4.0

v3.3.0

v3.2.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.1.1&new-version=4.1.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index b98d276c3..7ffd87247 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [3.1.0, dev] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 with: sdk: ${{ matrix.sdk }} From cc2dd7e0d3eac10fd31c84139afb606c4d36d5af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 May 2024 17:46:47 +0000 Subject: [PATCH 116/128] Bump actions/checkout from 4.1.2 to 4.1.4 (dart-lang/source_span#109) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.2 to 4.1.4.
Release notes

Sourced from actions/checkout's releases.

v4.1.4

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v4.1.3...v4.1.4

v4.1.3

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v4.1.2...v4.1.3

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.1.4

v4.1.3

v4.1.2

v4.1.1

v4.1.0

v4.0.0

v3.6.0

v3.5.3

v3.5.2

v3.5.1

v3.5.0

v3.4.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.1.2&new-version=4.1.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 7ffd87247..700581b5d 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [3.1.0, dev] steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 with: sdk: ${{ matrix.sdk }} From 04a0a06e8361e8821eac4c9cd2f59305d9a405bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 May 2024 17:54:04 +0000 Subject: [PATCH 117/128] Bump dart-lang/setup-dart from 1.6.2 to 1.6.4 (dart-lang/source_span#110) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart) from 1.6.2 to 1.6.4.
Release notes

Sourced from dart-lang/setup-dart's releases.

v1.6.4

  • Rebuild JS code to include changes from v1.6.3

v1.6.3

Changelog

Sourced from dart-lang/setup-dart's changelog.

v1.6.4

  • Rebuild JS code.

v1.6.3

v1.6.2

v1.6.1

  • Updated the google storage url for main channel releases.

v1.6.0

  • Enable provisioning of the latest Dart SDK patch release by specifying just the major and minor version (e.g. 3.2).

v1.5.1

  • No longer test the setup-dart action on pre-2.12 SDKs.
  • Upgrade JS interop code to use extension types (the new name for inline classes).
  • The upcoming rename of the be channel to main is now supported with forward compatibility that switches when the rename happens.

v1.5.0

  • Re-wrote the implementation of the action into Dart.
  • Auto-detect the platform architecture (x64, ia32, arm, arm64).
  • Improved the caching and download resilience of the sdk.
  • Added a new action output: dart-version - the installed version of the sdk.

v1.4.0

  • Automatically create OIDC token for pub.dev.
  • Add a reusable workflow for publishing.

v1.3.0

  • The install location of the Dart SDK is now available

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dart-lang/setup-dart&package-manager=github_actions&previous-version=1.6.2&new-version=1.6.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 700581b5d..dd6bc2bf0 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 + - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} - id: install @@ -50,7 +50,7 @@ jobs: sdk: [3.1.0, dev] steps: - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 + - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} - id: install From ac3a2874b0fc2219f6c2ffc6d064391cc248c345 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Mon, 13 May 2024 10:36:40 -0700 Subject: [PATCH 118/128] blast_repo fixes (dart-lang/source_span#111) dependabot --- pkgs/source_span/.github/dependabot.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkgs/source_span/.github/dependabot.yml b/pkgs/source_span/.github/dependabot.yml index c6531d433..eeaa9d9f4 100644 --- a/pkgs/source_span/.github/dependabot.yml +++ b/pkgs/source_span/.github/dependabot.yml @@ -10,3 +10,7 @@ updates: interval: monthly labels: - autosubmit + groups: + github-actions: + patterns: + - "*" From 2f14bd5b44b7e58ccd061110cc056e57562cc8dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 17:39:19 +0000 Subject: [PATCH 119/128] Bump actions/checkout from 4.1.4 to 4.1.5 in the github-actions group (dart-lang/source_span#112) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 4.1.4 to 4.1.5
Release notes

Sourced from actions/checkout's releases.

v4.1.5

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v4.1.4...v4.1.5

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.1.4&new-version=4.1.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index dd6bc2bf0..3324cef9d 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b + - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [3.1.0, dev] steps: - - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b + - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} From e652540a39a6808d39268e4b4dd7686a21195be9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jun 2024 17:28:04 +0000 Subject: [PATCH 120/128] Bump actions/checkout from 4.1.5 to 4.1.6 in the github-actions group (dart-lang/source_span#113) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 4.1.5 to 4.1.6
Release notes

Sourced from actions/checkout's releases.

v4.1.6

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v4.1.5...v4.1.6

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.1.6

v4.1.5

v4.1.4

v4.1.3

v4.1.2

v4.1.1

v4.1.0

v4.0.0

v3.6.0

v3.5.3

v3.5.2

v3.5.1

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.1.5&new-version=4.1.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 3324cef9d..a669c2886 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [3.1.0, dev] steps: - - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} From 9a76bf4e3d49330db6056c295a238abf795fe9a9 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Mon, 24 Jun 2024 10:03:16 -0700 Subject: [PATCH 121/128] bump lints (dart-lang/source_span#114) --- pkgs/source_span/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 45804e781..3a7624ba3 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -13,5 +13,5 @@ dependencies: term_glyph: ^1.2.0 dev_dependencies: - dart_flutter_team_lints: ^2.0.0 + dart_flutter_team_lints: ^3.0.0 test: ^1.16.0 From 23c8192219f3066b3065e7d8ba2e851ad409d605 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:09:52 +0000 Subject: [PATCH 122/128] Bump the github-actions group with 2 updates (dart-lang/source_span#115) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart). Updates `actions/checkout` from 4.1.6 to 4.1.7
Release notes

Sourced from actions/checkout's releases.

v4.1.7

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4.1.6...v4.1.7

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.1.7

v4.1.6

v4.1.5

v4.1.4

v4.1.3

v4.1.2

v4.1.1

v4.1.0

v4.0.0

v3.6.0

v3.5.3

... (truncated)

Commits

Updates `dart-lang/setup-dart` from 1.6.4 to 1.6.5
Release notes

Sourced from dart-lang/setup-dart's releases.

v1.6.5

dart-lang/source_span#118: dart-lang/setup-dartdart-lang/source_span#118

Changelog

Sourced from dart-lang/setup-dart's changelog.

v1.6.5

dart-lang/source_span#118: dart-lang/setup-dartdart-lang/source_span#118

v1.6.4

  • Rebuild JS code.

v1.6.3

v1.6.2

v1.6.1

  • Updated the google storage url for main channel releases.

v1.6.0

  • Enable provisioning of the latest Dart SDK patch release by specifying just the major and minor version (e.g. 3.2).

v1.5.1

  • No longer test the setup-dart action on pre-2.12 SDKs.
  • Upgrade JS interop code to use extension types (the new name for inline classes).
  • The upcoming rename of the be channel to main is now supported with forward compatibility that switches when the rename happens.

v1.5.0

  • Re-wrote the implementation of the action into Dart.
  • Auto-detect the platform architecture (x64, ia32, arm, arm64).
  • Improved the caching and download resilience of the sdk.
  • Added a new action output: dart-version - the installed version of the sdk.

v1.4.0

... (truncated)

Commits

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--- pkgs/source_span/.github/workflows/test-package.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index a669c2886..a0116f708 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,8 +22,8 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 - - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} - id: install @@ -49,8 +49,8 @@ jobs: os: [ubuntu-latest] sdk: [3.1.0, dev] steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 - - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} - id: install From edadad0d06ef1b7cf1eeb1a27c096a5d2bc184ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:31:06 +0000 Subject: [PATCH 123/128] Bump actions/checkout from 4.1.7 to 4.2.0 in the github-actions group (dart-lang/source_span#117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 4.1.7 to 4.2.0
Release notes

Sourced from actions/checkout's releases.

v4.2.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4.1.7...v4.2.0

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.2.0

v4.1.7

v4.1.6

v4.1.5

v4.1.4

v4.1.3

v4.1.2

v4.1.1

v4.1.0

v4.0.0

v3.6.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.1.7&new-version=4.2.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index a0116f708..d0c373b13 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [3.1.0, dev] steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} From 360c9446476b1ad968b540ab80f4bb303d8c001f Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Mon, 28 Oct 2024 14:50:55 -0700 Subject: [PATCH 124/128] blast_repo fixes (dart-lang/source_span#118) drop-lint --- pkgs/source_span/analysis_options.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/pkgs/source_span/analysis_options.yaml b/pkgs/source_span/analysis_options.yaml index ae73fa5e9..d2ebdbfe8 100644 --- a/pkgs/source_span/analysis_options.yaml +++ b/pkgs/source_span/analysis_options.yaml @@ -22,7 +22,6 @@ linter: - literal_only_boolean_expressions - missing_whitespace_between_adjacent_strings - no_adjacent_strings_in_list - - package_api_docs - prefer_const_declarations - prefer_expression_function_bodies - prefer_final_locals From 12a0c086e517cf313578574b67aa18d9e6b56060 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 17:36:26 +0000 Subject: [PATCH 125/128] Bump actions/checkout from 4.2.0 to 4.2.2 in the github-actions group (dart-lang/source_span#119) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 4.2.0 to 4.2.2
Release notes

Sourced from actions/checkout's releases.

v4.2.2

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v4.2.1...v4.2.2

v4.2.1

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4.2.0...v4.2.1

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.2.2

v4.2.1

v4.2.0

v4.1.7

v4.1.6

v4.1.5

v4.1.4

v4.1.3

v4.1.2

v4.1.1

v4.1.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.2.0&new-version=4.2.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index d0c373b13..77622fa83 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -22,7 +22,7 @@ jobs: matrix: sdk: [dev] steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} @@ -49,7 +49,7 @@ jobs: os: [ubuntu-latest] sdk: [3.1.0, dev] steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} From 4aec5835f0375e282b30462596102d79307b925c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2024 17:39:59 +0000 Subject: [PATCH 126/128] Bump dart-lang/setup-dart in the github-actions group (dart-lang/source_span#120) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the github-actions group with 1 update: [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart). Updates `dart-lang/setup-dart` from 1.6.5 to 1.7.0
Release notes

Sourced from dart-lang/setup-dart's releases.

v1.7.0

What's Changed

  • Install a Flutter SDK in the publish workflow allowing for publication of flutter packages.
Changelog

Sourced from dart-lang/setup-dart's changelog.

v1.7.0

v1.6.5

dart-lang/source_span#118: dart-lang/setup-dartdart-lang/source_span#118

v1.6.4

  • Rebuild JS code.

v1.6.3

v1.6.2

v1.6.1

  • Updated the google storage url for main channel releases.

v1.6.0

  • Enable provisioning of the latest Dart SDK patch release by specifying just the major and minor version (e.g. 3.2).

v1.5.1

  • No longer test the setup-dart action on pre-2.12 SDKs.
  • Upgrade JS interop code to use extension types (the new name for inline classes).
  • The upcoming rename of the be channel to main is now supported with forward compatibility that switches when the rename happens.

v1.5.0

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dart-lang/setup-dart&package-manager=github_actions&previous-version=1.6.5&new-version=1.7.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--- pkgs/source_span/.github/workflows/test-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/pkgs/source_span/.github/workflows/test-package.yml index 77622fa83..c8f1f52c7 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/pkgs/source_span/.github/workflows/test-package.yml @@ -23,7 +23,7 @@ jobs: sdk: [dev] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 + - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 with: sdk: ${{ matrix.sdk }} - id: install @@ -50,7 +50,7 @@ jobs: sdk: [3.1.0, dev] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 + - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 with: sdk: ${{ matrix.sdk }} - id: install From e62561bdcea9dfc1107d340837041233922767eb Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 10 Dec 2024 16:07:01 +0100 Subject: [PATCH 127/128] Add issue template and other fixes --- .github/ISSUE_TEMPLATE/source_span.md | 5 +++++ pkgs/source_span/pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .github/ISSUE_TEMPLATE/source_span.md diff --git a/.github/ISSUE_TEMPLATE/source_span.md b/.github/ISSUE_TEMPLATE/source_span.md new file mode 100644 index 000000000..7dbb3c4f8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/source_span.md @@ -0,0 +1,5 @@ +--- +name: "package:source_span" +about: "Create a bug or file a feature request against package:source_span." +labels: "package:source_span" +--- \ No newline at end of file diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 3a7624ba3..9c39d1488 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -2,7 +2,7 @@ name: source_span version: 1.10.1-wip description: >- Provides a standard representation for source code locations and spans. -repository: https://github.com/dart-lang/source_span +repository: https://github.com/dart-lang/tools/tree/main/pkgs/source_span environment: sdk: ^3.1.0 From 887264f8949ef2a0e14a7e8d86bda27d7e91d0c8 Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 10 Dec 2024 16:17:53 +0100 Subject: [PATCH 128/128] merge fixes --- .github/labeler.yml | 4 ++++ .../workflows/source_span.yaml | 17 ++++++++++++++--- README.md | 1 + pkgs/source_span/.github/dependabot.yml | 16 ---------------- pkgs/source_span/.github/workflows/publish.yaml | 14 -------------- pkgs/source_span/CHANGELOG.md | 3 ++- pkgs/source_span/README.md | 2 +- pkgs/source_span/pubspec.yaml | 2 +- 8 files changed, 23 insertions(+), 36 deletions(-) rename pkgs/source_span/.github/workflows/test-package.yml => .github/workflows/source_span.yaml (85%) delete mode 100644 pkgs/source_span/.github/dependabot.yml delete mode 100644 pkgs/source_span/.github/workflows/publish.yaml diff --git a/.github/labeler.yml b/.github/labeler.yml index eca80bbc2..de033db30 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -84,6 +84,10 @@ - changed-files: - any-glob-to-any-file: 'pkgs/source_map_stack_trace/**' +'package:source_span': + - changed-files: + - any-glob-to-any-file: 'pkgs/source_span/**' + 'package:unified_analytics': - changed-files: - any-glob-to-any-file: 'pkgs/unified_analytics/**' diff --git a/pkgs/source_span/.github/workflows/test-package.yml b/.github/workflows/source_span.yaml similarity index 85% rename from pkgs/source_span/.github/workflows/test-package.yml rename to .github/workflows/source_span.yaml index c8f1f52c7..2c2ba0548 100644 --- a/pkgs/source_span/.github/workflows/test-package.yml +++ b/.github/workflows/source_span.yaml @@ -1,17 +1,28 @@ -name: Dart CI +name: package:source_span on: # Run on PRs and pushes to the default branch. push: - branches: [ master ] + branches: [ main ] + paths: + - '.github/workflows/source_span.yml' + - 'pkgs/source_span/**' pull_request: - branches: [ master ] + branches: [ main ] + paths: + - '.github/workflows/source_span.yml' + - 'pkgs/source_span/**' schedule: - cron: "0 0 * * 0" env: PUB_ENVIRONMENT: bot.github + +defaults: + run: + working-directory: pkgs/source_span/ + jobs: # Check code formatting and static analysis on a single OS (linux) # against Dart dev. diff --git a/README.md b/README.md index 50517c36e..6b4fcf8a2 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ don't naturally belong to other topic monorepos (like | [mime](pkgs/mime/) | Utilities for handling media (MIME) types, including determining a type from a file extension and file contents. | [![package issues](https://img.shields.io/badge/package:mime-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Amime) | [![pub package](https://img.shields.io/pub/v/mime.svg)](https://pub.dev/packages/mime) | | [oauth2](pkgs/oauth2/) | A client library for authenticating with a remote service via OAuth2 on behalf of a user, and making authorized HTTP requests with the user's OAuth2 credentials. | [![package issues](https://img.shields.io/badge/package:oauth2-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aoauth2) | [![pub package](https://img.shields.io/pub/v/oauth2.svg)](https://pub.dev/packages/oauth2) | | [source_map_stack_trace](pkgs/source_map_stack_trace/) | A package for applying source maps to stack traces. | [![package issues](https://img.shields.io/badge/package:source_map_stack_trace-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Asource_map_stack_trace) | [![pub package](https://img.shields.io/pub/v/source_map_stack_trace.svg)](https://pub.dev/packages/source_map_stack_trace) | +| [source_span](pkgs/source_span/) | Provides a standard representation for source code locations and spans. | [![package issues](https://img.shields.io/badge/package:source_span-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Asource_span) | [![pub package](https://img.shields.io/pub/v/source_span.svg)](https://pub.dev/packages/source_span) | | [unified_analytics](pkgs/unified_analytics/) | A package for logging analytics for all Dart and Flutter related tooling to Google Analytics. | [![package issues](https://img.shields.io/badge/package:unified_analytics-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aunified_analytics) | [![pub package](https://img.shields.io/pub/v/unified_analytics.svg)](https://pub.dev/packages/unified_analytics) | ## Publishing automation diff --git a/pkgs/source_span/.github/dependabot.yml b/pkgs/source_span/.github/dependabot.yml deleted file mode 100644 index eeaa9d9f4..000000000 --- a/pkgs/source_span/.github/dependabot.yml +++ /dev/null @@ -1,16 +0,0 @@ -# Set update schedule for GitHub Actions -# See https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot - -version: 2 -updates: - -- package-ecosystem: github-actions - directory: / - schedule: - interval: monthly - labels: - - autosubmit - groups: - github-actions: - patterns: - - "*" diff --git a/pkgs/source_span/.github/workflows/publish.yaml b/pkgs/source_span/.github/workflows/publish.yaml deleted file mode 100644 index 2239b63d3..000000000 --- a/pkgs/source_span/.github/workflows/publish.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# A CI configuration to auto-publish pub packages. - -name: Publish - -on: - pull_request: - branches: [ master ] - push: - tags: [ 'v[0-9]+.[0-9]+.[0-9]+' ] - -jobs: - publish: - if: ${{ github.repository_owner == 'dart-lang' }} - uses: dart-lang/ecosystem/.github/workflows/publish.yaml@main diff --git a/pkgs/source_span/CHANGELOG.md b/pkgs/source_span/CHANGELOG.md index f46c1614b..b8319d773 100644 --- a/pkgs/source_span/CHANGELOG.md +++ b/pkgs/source_span/CHANGELOG.md @@ -1,6 +1,7 @@ -## 1.10.1-wip +## 1.10.1 * Require Dart 3.1 +* Move to `dart-lang/tools` monorepo. ## 1.10.0 diff --git a/pkgs/source_span/README.md b/pkgs/source_span/README.md index 0faf0cbc4..b4ce25fcf 100644 --- a/pkgs/source_span/README.md +++ b/pkgs/source_span/README.md @@ -1,4 +1,4 @@ -[![Dart CI](https://github.com/dart-lang/source_span/actions/workflows/test-package.yml/badge.svg)](https://github.com/dart-lang/source_span/actions/workflows/test-package.yml) +[![Build Status](https://github.com/dart-lang/tools/actions/workflows/source_span.yaml/badge.svg)](https://github.com/dart-lang/tools/actions/workflows/source_span.yaml) [![pub package](https://img.shields.io/pub/v/source_span.svg)](https://pub.dev/packages/source_span) [![package publisher](https://img.shields.io/pub/publisher/source_span.svg)](https://pub.dev/packages/source_span/publisher) diff --git a/pkgs/source_span/pubspec.yaml b/pkgs/source_span/pubspec.yaml index 9c39d1488..8757b2dee 100644 --- a/pkgs/source_span/pubspec.yaml +++ b/pkgs/source_span/pubspec.yaml @@ -1,5 +1,5 @@ name: source_span -version: 1.10.1-wip +version: 1.10.1 description: >- Provides a standard representation for source code locations and spans. repository: https://github.com/dart-lang/tools/tree/main/pkgs/source_span