Merge the null_safety branch into master (dart-lang/string_scanner#22)
diff --git a/pkgs/string_scanner/.travis.yml b/pkgs/string_scanner/.travis.yml index 48e46ca..dd4f437 100644 --- a/pkgs/string_scanner/.travis.yml +++ b/pkgs/string_scanner/.travis.yml
@@ -2,7 +2,6 @@ dart: - dev - - 2.0.0 dart_task: - test: --platform vm,chrome @@ -15,13 +14,10 @@ - dart: dev dart_task: dartanalyzer: --fatal-warnings --fatal-hints . - - dart: 2.0.0 - dart_task: - dartanalyzer: --fatal-warnings . # 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/string_scanner/CHANGELOG.md b/pkgs/string_scanner/CHANGELOG.md index fb7f74d..abe488c 100644 --- a/pkgs/string_scanner/CHANGELOG.md +++ b/pkgs/string_scanner/CHANGELOG.md
@@ -1,3 +1,7 @@ +## 1.1.0-nullsafety + +- Migrate to null safety. + ## 1.0.5 - Added an example.
diff --git a/pkgs/string_scanner/analysis_options.yaml b/pkgs/string_scanner/analysis_options.yaml index 60abe63..2407da6 100644 --- a/pkgs/string_scanner/analysis_options.yaml +++ b/pkgs/string_scanner/analysis_options.yaml
@@ -4,6 +4,9 @@ strong-mode: implicit-casts: false + enable-experiment: + - non-nullable + linter: rules: - avoid_bool_literals_in_conditional_expressions
diff --git a/pkgs/string_scanner/example/example.dart b/pkgs/string_scanner/example/example.dart index e92677f..fd36a73 100644 --- a/pkgs/string_scanner/example/example.dart +++ b/pkgs/string_scanner/example/example.dart
@@ -24,11 +24,11 @@ // [Scanner.lastMatch] holds the [MatchData] for the most recent call to // [Scanner.scan], [Scanner.expect], or [Scanner.matches]. - var number = num.parse(scanner.lastMatch[0]); + var number = num.parse((scanner.lastMatch![0])!); if (scanner.scan('.')) { scanner.expect(RegExp(r'\d+')); - final decimal = scanner.lastMatch[0]; + final decimal = scanner.lastMatch![0]!; number += int.parse(decimal) / math.pow(10, decimal.length); }
diff --git a/pkgs/string_scanner/lib/src/eager_span_scanner.dart b/pkgs/string_scanner/lib/src/eager_span_scanner.dart index 848cb72..415b9f3 100644 --- a/pkgs/string_scanner/lib/src/eager_span_scanner.dart +++ b/pkgs/string_scanner/lib/src/eager_span_scanner.dart
@@ -31,8 +31,7 @@ @override set state(LineScannerState state) { - if (state is! _EagerSpanScannerState || - !identical((state as _EagerSpanScannerState)._scanner, this)) { + if (state is! _EagerSpanScannerState || !identical(state._scanner, this)) { throw ArgumentError('The given LineScannerState was not returned by ' 'this LineScanner.'); } @@ -69,7 +68,7 @@ } } - EagerSpanScanner(String string, {sourceUrl, int position}) + EagerSpanScanner(String string, {sourceUrl, int? position}) : super(string, sourceUrl: sourceUrl, position: position); @override @@ -99,13 +98,14 @@ @override bool scan(Pattern pattern) { if (!super.scan(pattern)) return false; + final firstMatch = (lastMatch![0])!; - final newlines = _newlinesIn(lastMatch[0]); + final newlines = _newlinesIn(firstMatch); _line += newlines.length; if (newlines.isEmpty) { - _column += lastMatch[0].length; + _column += firstMatch.length; } else { - _column = lastMatch[0].length - newlines.last.end; + _column = firstMatch.length - newlines.last.end; } return true;
diff --git a/pkgs/string_scanner/lib/src/exception.dart b/pkgs/string_scanner/lib/src/exception.dart index 8c994b5..8aa7aab 100644 --- a/pkgs/string_scanner/lib/src/exception.dart +++ b/pkgs/string_scanner/lib/src/exception.dart
@@ -14,7 +14,7 @@ /// The URL of the source file being parsed. /// /// This may be `null`, indicating that the source URL is unknown. - Uri get sourceUrl => span.sourceUrl; + Uri? get sourceUrl => span?.sourceUrl; StringScannerException(String message, SourceSpan span, String source) : super(message, span, source);
diff --git a/pkgs/string_scanner/lib/src/line_scanner.dart b/pkgs/string_scanner/lib/src/line_scanner.dart index 9e7d918..358d4c1 100644 --- a/pkgs/string_scanner/lib/src/line_scanner.dart +++ b/pkgs/string_scanner/lib/src/line_scanner.dart
@@ -73,7 +73,7 @@ } } - LineScanner(String string, {sourceUrl, int position}) + LineScanner(String string, {sourceUrl, int? position}) : super(string, sourceUrl: sourceUrl, position: position); @override @@ -104,12 +104,12 @@ bool scan(Pattern pattern) { if (!super.scan(pattern)) return false; - final newlines = _newlinesIn(lastMatch[0]); + final newlines = _newlinesIn(lastMatch![0]!); _line += newlines.length; if (newlines.isEmpty) { - _column += lastMatch[0].length; + _column += (lastMatch![0])!.length; } else { - _column = lastMatch[0].length - newlines.last.end; + _column = (lastMatch![0])!.length - newlines.last.end; } return true;
diff --git a/pkgs/string_scanner/lib/src/relative_span_scanner.dart b/pkgs/string_scanner/lib/src/relative_span_scanner.dart index a7a035a..150d507 100644 --- a/pkgs/string_scanner/lib/src/relative_span_scanner.dart +++ b/pkgs/string_scanner/lib/src/relative_span_scanner.dart
@@ -47,8 +47,7 @@ @override set state(LineScannerState state) { - if (state is! _SpanScannerState || - !identical((state as _SpanScannerState)._scanner, this)) { + if (state is! _SpanScannerState || !identical(state._scanner, this)) { throw ArgumentError('The given LineScannerState was not returned by ' 'this LineScanner.'); } @@ -57,8 +56,8 @@ } @override - FileSpan get lastSpan => _lastSpan; - FileSpan _lastSpan; + FileSpan? get lastSpan => _lastSpan; + FileSpan? _lastSpan; @override FileLocation get location => @@ -73,7 +72,7 @@ super(span.text, sourceUrl: span.sourceUrl); @override - FileSpan spanFrom(LineScannerState startState, [LineScannerState endState]) { + FileSpan spanFrom(LineScannerState startState, [LineScannerState? endState]) { final endPosition = endState == null ? position : endState.position; return _sourceFile.span(_startLocation.offset + startState.position, _startLocation.offset + endPosition); @@ -87,12 +86,12 @@ } _lastSpan = _sourceFile.span(_startLocation.offset + position, - _startLocation.offset + lastMatch.end); + _startLocation.offset + lastMatch!.end); return true; } @override - void error(String message, {Match match, int position, int length}) { + Never error(String message, {Match? match, int? position, int? length}) { validateErrorArgs(string, match, position, length); if (match == null && position == null && length == null) match = lastMatch;
diff --git a/pkgs/string_scanner/lib/src/span_scanner.dart b/pkgs/string_scanner/lib/src/span_scanner.dart index 1a8ca2a..806a8f8 100644 --- a/pkgs/string_scanner/lib/src/span_scanner.dart +++ b/pkgs/string_scanner/lib/src/span_scanner.dart
@@ -29,8 +29,7 @@ @override set state(LineScannerState state) { - if (state is! _SpanScannerState || - !identical((state as _SpanScannerState)._scanner, this)) { + if (state is! _SpanScannerState || !identical(state._scanner, this)) { throw ArgumentError('The given LineScannerState was not returned by ' 'this LineScanner.'); } @@ -42,12 +41,12 @@ /// /// This is the span for the entire match. There's no way to get spans for /// subgroups since [Match] exposes no information about their positions. - FileSpan get lastSpan { + FileSpan? get lastSpan { if (lastMatch == null) _lastSpan = null; return _lastSpan; } - FileSpan _lastSpan; + FileSpan? _lastSpan; /// The current location of the scanner. FileLocation get location => _sourceFile.location(position); @@ -60,7 +59,7 @@ /// [sourceUrl] is used as [SourceLocation.sourceUrl] for the returned /// [FileSpan]s as well as for error reporting. It can be a [String], a /// [Uri], or `null`. - SpanScanner(String string, {sourceUrl, int position}) + SpanScanner(String string, {sourceUrl, int? position}) : _sourceFile = SourceFile.fromString(string, url: sourceUrl), super(string, sourceUrl: sourceUrl, position: position); @@ -75,7 +74,7 @@ /// itself and its `LineScannerState` are eagerly computed. To limit their /// memory footprint, returned spans and locations will still lazily compute /// their line and column numbers. - factory SpanScanner.eager(String string, {sourceUrl, int position}) = + factory SpanScanner.eager(String string, {sourceUrl, int? position}) = EagerSpanScanner; /// Creates a new [SpanScanner] that scans within [span]. @@ -88,7 +87,7 @@ /// Creates a [FileSpan] representing the source range between [startState] /// and the current position. - FileSpan spanFrom(LineScannerState startState, [LineScannerState endState]) { + FileSpan spanFrom(LineScannerState startState, [LineScannerState? endState]) { final endPosition = endState == null ? position : endState.position; return _sourceFile.span(startState.position, endPosition); } @@ -100,12 +99,12 @@ return false; } - _lastSpan = _sourceFile.span(position, lastMatch.end); + _lastSpan = _sourceFile.span(position, lastMatch!.end); return true; } @override - void error(String message, {Match match, int position, int length}) { + Never error(String message, {Match? match, int? position, int? length}) { validateErrorArgs(string, match, position, length); if (match == null && position == null && length == null) match = lastMatch;
diff --git a/pkgs/string_scanner/lib/src/string_scanner.dart b/pkgs/string_scanner/lib/src/string_scanner.dart index 55ff17d..f29bc3a 100644 --- a/pkgs/string_scanner/lib/src/string_scanner.dart +++ b/pkgs/string_scanner/lib/src/string_scanner.dart
@@ -3,7 +3,6 @@ // BSD-style license that can be found in the LICENSE file. import 'package:charcode/charcode.dart'; -import 'package:meta/meta.dart'; import 'package:source_span/source_span.dart'; import 'exception.dart'; @@ -15,7 +14,7 @@ /// /// This is used for error reporting. It may be `null`, indicating that the /// source URL is unknown or unavailable. - final Uri sourceUrl; + final Uri? sourceUrl; /// The string being scanned through. final String string; @@ -36,15 +35,15 @@ /// The data about the previous match made by the scanner. /// /// If the last match failed, this will be `null`. - Match get lastMatch { + Match? get lastMatch { // Lazily unset [_lastMatch] so that we avoid extra assignments in // character-by-character methods that are used in core loops. if (_position != _lastMatchPosition) _lastMatch = null; return _lastMatch; } - Match _lastMatch; - int _lastMatchPosition; + Match? _lastMatch; + int? _lastMatchPosition; /// The portion of the string that hasn't yet been scanned. String get rest => string.substring(position); @@ -57,9 +56,10 @@ /// [position] defaults to 0, the beginning of the string. [sourceUrl] is the /// URL of the source of the string being scanned, if available. It can be /// a [String], a [Uri], or `null`. - StringScanner(this.string, {sourceUrl, int position}) - : sourceUrl = - sourceUrl is String ? Uri.parse(sourceUrl) : sourceUrl as Uri { + StringScanner(this.string, {sourceUrl, int? position}) + : sourceUrl = sourceUrl == null + ? null + : sourceUrl is String ? Uri.parse(sourceUrl) : sourceUrl as Uri { if (position != null) this.position = position; } @@ -79,7 +79,7 @@ /// /// This returns `null` if [offset] points outside the string. It doesn't /// affect [lastMatch]. - int peekChar([int offset]) { + int? peekChar([int? offset]) { offset ??= 0; final index = position + offset; if (index < 0 || index >= string.length) return null; @@ -102,7 +102,7 @@ /// describing the position of the failure. [name] is used in this error as /// the expected name of the character being matched; if it's `null`, the /// character itself is used instead. - void expectChar(int character, {String name}) { + void expectChar(int character, {String? name}) { if (scanChar(character)) return; if (name == null) { @@ -125,7 +125,7 @@ bool scan(Pattern pattern) { final success = matches(pattern); if (success) { - _position = _lastMatch.end; + _position = _lastMatch!.end; _lastMatchPosition = _position; } return success; @@ -138,7 +138,7 @@ /// position of the failure. [name] is used in this error as the expected name /// of the pattern being matched; if it's `null`, the pattern itself is used /// instead. - void expect(Pattern pattern, {String name}) { + void expect(Pattern pattern, {String? name}) { if (scan(pattern)) return; if (name == null) { @@ -175,7 +175,7 @@ /// /// Unlike [String.substring], [end] defaults to [position] rather than the /// end of the string. - String substring(int start, [int end]) { + String substring(int start, [int? end]) { end ??= position; return string.substring(start, end); } @@ -193,8 +193,7 @@ /// position; if only [position] is passed, [length] defaults to 0. /// /// It's an error to pass [match] at the same time as [position] or [length]. - @alwaysThrows - void error(String message, {Match match, int position, int length}) { + Never error(String message, {Match? match, int? position, int? length}) { validateErrorArgs(string, match, position, length); if (match == null && position == null && length == null) match = lastMatch; @@ -209,7 +208,7 @@ // TODO(nweiz): Make this handle long lines more gracefully. /// Throws a [FormatException] describing that [name] is expected at the /// current position in the string. - void _fail(String name) { + Never _fail(String name) { error('expected $name.', position: position, length: 0); } }
diff --git a/pkgs/string_scanner/lib/src/utils.dart b/pkgs/string_scanner/lib/src/utils.dart index 7fe3d52..52dfb63 100644 --- a/pkgs/string_scanner/lib/src/utils.dart +++ b/pkgs/string_scanner/lib/src/utils.dart
@@ -5,7 +5,8 @@ import 'string_scanner.dart'; /// Validates the arguments passed to [StringScanner.error]. -void validateErrorArgs(String string, Match match, int position, int length) { +void validateErrorArgs( + String string, Match? match, int? position, int? length) { if (match != null && (position != null || length != null)) { throw ArgumentError("Can't pass both match and position/length."); }
diff --git a/pkgs/string_scanner/pubspec.yaml b/pkgs/string_scanner/pubspec.yaml index d5cefce..7a9826d 100644 --- a/pkgs/string_scanner/pubspec.yaml +++ b/pkgs/string_scanner/pubspec.yaml
@@ -1,17 +1,90 @@ name: string_scanner -version: 1.0.5 +version: 1.1.0-nullsafety description: A class for parsing strings using a sequence of patterns. homepage: https://github.com/dart-lang/string_scanner environment: - sdk: '>=2.0.0 <3.0.0' + sdk: '>=2.9.0-18.0 <2.9.0' dependencies: - charcode: ^1.1.0 - meta: ^1.1.0 - source_span: ^1.4.0 + charcode: '>=1.2.0-nullsafety <1.2.0' + source_span: '>=1.8.0-nullsafety <1.8.0' dev_dependencies: - test: ^1.0.0 + test: '>=1.16.0-nullsafety <1.16.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 + source_span: + git: + url: git://github.com/dart-lang/source_span.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 + 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/string_scanner/test/error_test.dart b/pkgs/string_scanner/test/error_test.dart index 6173040..1f98c32 100644 --- a/pkgs/string_scanner/test/error_test.dart +++ b/pkgs/string_scanner/test/error_test.dart
@@ -106,7 +106,7 @@ }); group('argument errors', () { - StringScanner scanner; + late StringScanner scanner; setUp(() { scanner = StringScanner('foo bar baz'); scanner.scan('foo');
diff --git a/pkgs/string_scanner/test/line_scanner_test.dart b/pkgs/string_scanner/test/line_scanner_test.dart index aafc74a..0bbd499 100644 --- a/pkgs/string_scanner/test/line_scanner_test.dart +++ b/pkgs/string_scanner/test/line_scanner_test.dart
@@ -7,7 +7,7 @@ import 'package:test/test.dart'; void main() { - LineScanner scanner; + late LineScanner scanner; setUp(() { scanner = LineScanner('foo\nbar\r\nbaz'); });
diff --git a/pkgs/string_scanner/test/span_scanner_test.dart b/pkgs/string_scanner/test/span_scanner_test.dart index 2034d0a..828745f 100644 --- a/pkgs/string_scanner/test/span_scanner_test.dart +++ b/pkgs/string_scanner/test/span_scanner_test.dart
@@ -11,19 +11,19 @@ void main() { testForImplementation( 'lazy', - ([String string]) => + ([String? string]) => SpanScanner(string ?? 'foo\nbar\nbaz', sourceUrl: 'source')); testForImplementation( 'eager', - ([String string]) => + ([String? string]) => SpanScanner.eager(string ?? 'foo\nbar\nbaz', sourceUrl: 'source')); group('within', () { const text = 'first\nbefore: foo\nbar\nbaz :after\nlast'; final startOffset = text.indexOf('foo'); - SpanScanner scanner; + late SpanScanner scanner; setUp(() { final file = SourceFile.fromString(text, url: 'source'); scanner = @@ -51,7 +51,7 @@ scanner.scan('fo'); scanner.scan('o\nba'); - final span = scanner.lastSpan; + final span = scanner.lastSpan!; expect(span.start.offset, equals(startOffset + 2)); expect(span.start.line, equals(1)); expect(span.start.column, equals(10)); @@ -108,14 +108,14 @@ void testForImplementation( String name, SpanScanner Function([String string]) create) { group('for a $name scanner', () { - SpanScanner scanner; + late SpanScanner scanner; setUp(() => scanner = create()); test('tracks the span for the last match', () { scanner.scan('fo'); scanner.scan('o\nba'); - final span = scanner.lastSpan; + final span = scanner.lastSpan!; expect(span.start.offset, equals(2)); expect(span.start.line, equals(0)); expect(span.start.column, equals(2));
diff --git a/pkgs/string_scanner/test/string_scanner_test.dart b/pkgs/string_scanner/test/string_scanner_test.dart index 9dee9d1..0327499 100644 --- a/pkgs/string_scanner/test/string_scanner_test.dart +++ b/pkgs/string_scanner/test/string_scanner_test.dart
@@ -8,7 +8,7 @@ void main() { group('with an empty string', () { - StringScanner scanner; + late StringScanner scanner; setUp(() { scanner = StringScanner(''); }); @@ -90,7 +90,7 @@ }); group('at the beginning of a string', () { - StringScanner scanner; + late StringScanner scanner; setUp(() { scanner = StringScanner('foo bar'); }); @@ -156,7 +156,7 @@ test('a matching scan returns true and changes the state', () { expect(scanner.scan(RegExp('f(..)')), isTrue); - expect(scanner.lastMatch[1], equals('oo')); + expect(scanner.lastMatch![1], equals('oo')); expect(scanner.position, equals(3)); expect(scanner.rest, equals(' bar')); }); @@ -173,7 +173,7 @@ test('a matching expect changes the state', () { scanner.expect(RegExp('f(..)')); - expect(scanner.lastMatch[1], equals('oo')); + expect(scanner.lastMatch![1], equals('oo')); expect(scanner.position, equals(3)); expect(scanner.rest, equals(' bar')); }); @@ -192,7 +192,7 @@ test('a matching matches returns true and only changes lastMatch', () { expect(scanner.matches(RegExp('f(..)')), isTrue); - expect(scanner.lastMatch[1], equals('oo')); + expect(scanner.lastMatch![1], equals('oo')); expect(scanner.position, equals(0)); expect(scanner.rest, equals('foo bar')); }); @@ -223,7 +223,7 @@ expect(scanner.rest, equals('oo bar')); expect(scanner.scan(RegExp('oo.')), isTrue); - expect(scanner.lastMatch[0], equals('oo ')); + expect(scanner.lastMatch![0], equals('oo ')); expect(scanner.position, equals(4)); expect(scanner.rest, equals('bar')); }); @@ -242,19 +242,19 @@ test('scan accepts any Pattern', () { expect(scanner.scan('foo'), isTrue); - expect(scanner.lastMatch[0], equals('foo')); + expect(scanner.lastMatch![0], equals('foo')); expect(scanner.position, equals(3)); expect(scanner.rest, equals(' bar')); }); test('scans multiple times', () { expect(scanner.scan(RegExp('f(..)')), isTrue); - expect(scanner.lastMatch[1], equals('oo')); + expect(scanner.lastMatch![1], equals('oo')); expect(scanner.position, equals(3)); expect(scanner.rest, equals(' bar')); expect(scanner.scan(RegExp(' b(..)')), isTrue); - expect(scanner.lastMatch[1], equals('ar')); + expect(scanner.lastMatch![1], equals('ar')); expect(scanner.position, equals(7)); expect(scanner.rest, equals('')); expect(scanner.isDone, isTrue); @@ -263,7 +263,7 @@ }); group('after a scan', () { - StringScanner scanner; + late StringScanner scanner; setUp(() { scanner = StringScanner('foo bar'); expect(scanner.scan('foo'), isTrue); @@ -289,7 +289,7 @@ }); group('at the end of a string', () { - StringScanner scanner; + late StringScanner scanner; setUp(() { scanner = StringScanner('foo bar'); expect(scanner.scan('foo bar'), isTrue); @@ -368,7 +368,7 @@ expect(scanner.rest, equals('oo bar')); expect(scanner.scan(RegExp('oo.')), isTrue); - expect(scanner.lastMatch[0], equals('oo ')); + expect(scanner.lastMatch![0], equals('oo ')); expect(scanner.position, equals(4)); expect(scanner.rest, equals('bar')); }); @@ -400,7 +400,7 @@ expect(scanner.rest, equals('oo bar')); expect(scanner.scan(RegExp('oo.')), isTrue); - expect(scanner.lastMatch[0], equals('oo ')); + expect(scanner.lastMatch![0], equals('oo ')); expect(scanner.position, equals(4)); expect(scanner.rest, equals('bar')); });
diff --git a/pkgs/string_scanner/test/utils.dart b/pkgs/string_scanner/test/utils.dart index 676b695..ca03c06 100644 --- a/pkgs/string_scanner/test/utils.dart +++ b/pkgs/string_scanner/test/utils.dart
@@ -9,4 +9,4 @@ /// [StringScannerException] with the given [text]. Matcher throwsStringScannerException(String text) => throwsA(const TypeMatcher<StringScannerException>() - .having((e) => e.span.text, 'span.text', text)); + .having((e) => e.span!.text, 'span.text', text));