From 4c1605d7953c4c3d9208cf67d4aa9c6c1b60b252 Mon Sep 17 00:00:00 2001 From: pq Date: Fri, 6 Nov 2020 22:02:35 -0800 Subject: [PATCH 01/15] migrate to nnbd --- lib/src/event.dart | 20 ++++---- lib/src/loader.dart | 18 +++---- lib/src/null_span.dart | 1 + lib/src/parser.dart | 84 ++++++++++++++++---------------- lib/src/scanner.dart | 30 ++++++------ lib/src/token.dart | 7 +-- lib/src/utils.dart | 10 ++-- lib/src/yaml_document.dart | 2 +- lib/src/yaml_exception.dart | 2 +- lib/src/yaml_node.dart | 4 +- lib/src/yaml_node_wrapper.dart | 6 +-- pubspec.yaml | 16 +++--- test/span_test.dart | 18 +++---- test/utils.dart | 2 +- test/yaml_node_wrapper_test.dart | 8 +-- test/yaml_test.dart | 32 ++++++------ 16 files changed, 128 insertions(+), 132 deletions(-) diff --git a/lib/src/event.dart b/lib/src/event.dart index c4f6a6ddb1ab9..e8879eefcabd2 100644 --- a/lib/src/event.dart +++ b/lib/src/event.dart @@ -26,7 +26,7 @@ class DocumentStartEvent implements Event { final FileSpan span; /// The document's `%YAML` directive, or `null` if there was none. - final VersionDirective versionDirective; + final VersionDirective? versionDirective; /// The document's `%TAG` directives, if any. final List tagDirectives; @@ -37,7 +37,7 @@ class DocumentStartEvent implements Event { DocumentStartEvent(this.span, {this.versionDirective, - List tagDirectives, + List? tagDirectives, this.isImplicit = true}) : tagDirectives = tagDirectives ?? []; @@ -81,10 +81,10 @@ class AliasEvent implements Event { /// An event that can have associated anchor and tag properties. abstract class _ValueEvent implements Event { /// The name of the value's anchor, or `null` if it wasn't anchored. - String get anchor; + String? get anchor; /// The text of the value's tag, or `null` if it wasn't tagged. - String get tag; + String? get tag; @override String toString() { @@ -102,9 +102,9 @@ class ScalarEvent extends _ValueEvent { @override final FileSpan span; @override - final String anchor; + final String? anchor; @override - final String tag; + final String? tag; /// The contents of the scalar. final String value; @@ -125,9 +125,9 @@ class SequenceStartEvent extends _ValueEvent { @override final FileSpan span; @override - final String anchor; + final String? anchor; @override - final String tag; + final String? tag; /// The style of the collection in the original source. final CollectionStyle style; @@ -142,9 +142,9 @@ class MappingStartEvent extends _ValueEvent { @override final FileSpan span; @override - final String anchor; + final String? anchor; @override - final String tag; + final String? tag; /// The style of the collection in the original source. final CollectionStyle style; diff --git a/lib/src/loader.dart b/lib/src/loader.dart index 54172b5383af5..370540609a98e 100644 --- a/lib/src/loader.dart +++ b/lib/src/loader.dart @@ -27,7 +27,7 @@ class Loader { /// The span of the entire stream emitted so far. FileSpan get span => _span; - FileSpan _span; + late FileSpan _span; /// Creates a loader that loads [source]. /// @@ -42,7 +42,7 @@ class Loader { /// Loads the next document from the stream. /// /// If there are no more documents, returns `null`. - YamlDocument load() { + YamlDocument? load() { if (_parser.isDone) return null; var event = _parser.parse(); @@ -90,7 +90,7 @@ class Loader { } /// Registers an anchor. - void _registerAnchor(String anchor, YamlNode node) { + void _registerAnchor(String? anchor, YamlNode node) { if (anchor == null) return; // libyaml throws an error for duplicate anchors, but example 7.1 makes it @@ -207,7 +207,7 @@ class Loader { /// /// If parsing fails, this returns `null`, indicating that the scalar should /// be parsed as a string. - YamlScalar _tryParseScalar(ScalarEvent scalar) { + YamlScalar? _tryParseScalar(ScalarEvent scalar) { // Quickly check for the empty string, which means null. var length = scalar.value.length; if (length == 0) return YamlScalar.internal(null, scalar); @@ -239,7 +239,7 @@ class Loader { /// Parse a null scalar. /// /// Returns a Dart `null` if parsing fails. - YamlScalar _parseNull(ScalarEvent scalar) { + YamlScalar? _parseNull(ScalarEvent scalar) { switch (scalar.value) { case '': case 'null': @@ -255,7 +255,7 @@ class Loader { /// Parse a boolean scalar. /// /// Returns `null` if parsing fails. - YamlScalar _parseBool(ScalarEvent scalar) { + YamlScalar? _parseBool(ScalarEvent scalar) { switch (scalar.value) { case 'true': case 'True': @@ -273,7 +273,7 @@ class Loader { /// Parses a numeric scalar. /// /// Returns `null` if parsing fails. - YamlScalar _parseNumber(ScalarEvent scalar, + YamlScalar? _parseNumber(ScalarEvent scalar, {bool allowInt = true, bool allowFloat = true}) { var value = _parseNumberValue(scalar.value, allowInt: allowInt, allowFloat: allowFloat); @@ -283,7 +283,7 @@ class Loader { /// Parses the value of a number. /// /// Returns the number if it's parsed successfully, or `null` if it's not. - num _parseNumberValue(String contents, + num? _parseNumberValue(String contents, {bool allowInt = true, bool allowFloat = true}) { assert(allowInt || allowFloat); @@ -315,7 +315,7 @@ class Loader { secondChar >= $0 && secondChar <= $9)) { // Try to parse an int or, failing that, a double. - num result; + num? result; if (allowInt) { // Pass "radix: 10" explicitly to ensure that "-0x10", which is valid // Dart but invalid YAML, doesn't get parsed. diff --git a/lib/src/null_span.dart b/lib/src/null_span.dart index 64b3551ed79f0..dd868b808fb5a 100644 --- a/lib/src/null_span.dart +++ b/lib/src/null_span.dart @@ -12,6 +12,7 @@ import 'package:source_span/source_span.dart'; class NullSpan extends SourceSpanMixin { @override final SourceLocation start; + @override SourceLocation get end => start; @override diff --git a/lib/src/parser.dart b/lib/src/parser.dart index 4c8aaaf61af7d..267d7cadf7430 100644 --- a/lib/src/parser.dart +++ b/lib/src/parser.dart @@ -130,7 +130,7 @@ class Parser { /// DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* /// ************************* Event _parseDocumentStart() { - var token = _scanner.peek(); + var token = _scanner.peek()!; // libyaml requires any document beyond the first in the stream to have an // explicit document start indicator, but the spec allows it to be omitted @@ -138,7 +138,7 @@ class Parser { // Parse extra document end indicators. while (token.type == TokenType.documentEnd) { - token = _scanner.advance(); + token = _scanner.advance()!; } if (token.type != TokenType.versionDirective && @@ -163,7 +163,7 @@ class Parser { var pair = _processDirectives(); var versionDirective = pair.first; var tagDirectives = pair.last; - token = _scanner.peek(); + token = _scanner.peek()!; if (token.type != TokenType.documentStart) { throw YamlException('Expected document start.', token.span); } @@ -183,7 +183,7 @@ class Parser { /// DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* /// *********** Event _parseDocumentContent() { - var token = _scanner.peek(); + var token = _scanner.peek()!; switch (token.type) { case TokenType.versionDirective: @@ -209,7 +209,7 @@ class Parser { _tagDirectives.clear(); _state = _State.DOCUMENT_START; - var token = _scanner.peek(); + var token = _scanner.peek()!; if (token.type == TokenType.documentEnd) { _scanner.scan(); return DocumentEndEvent(token.span, isImplicit: false); @@ -246,7 +246,7 @@ class Parser { /// flow_content ::= flow_collection | SCALAR /// ****** Event _parseNode({bool block = false, bool indentlessSequence = false}) { - var token = _scanner.peek(); + var token = _scanner.peek()!; if (token is AliasToken) { _scanner.scan(); @@ -254,40 +254,40 @@ class Parser { return AliasEvent(token.span, token.name); } - String anchor; - TagToken tagToken; + String? anchor; + TagToken? tagToken; var span = token.span.start.pointSpan(); Token parseAnchor(AnchorToken token) { anchor = token.name; span = span.expand(token.span); - return _scanner.advance(); + return _scanner.advance()!; } Token parseTag(TagToken token) { tagToken = token; span = span.expand(token.span); - return _scanner.advance(); + return _scanner.advance()!; } if (token is AnchorToken) { - token = parseAnchor(token as AnchorToken); - if (token is TagToken) token = parseTag(token as TagToken); + token = parseAnchor(token); + if (token is TagToken) token = parseTag(token); } else if (token is TagToken) { - token = parseTag(token as TagToken); - if (token is AnchorToken) token = parseAnchor(token as AnchorToken); + token = parseTag(token); + if (token is AnchorToken) token = parseAnchor(token); } - String tag; + String? tag; if (tagToken != null) { - if (tagToken.handle == null) { - tag = tagToken.suffix; + if (tagToken!.handle == null) { + tag = tagToken!.suffix; } else { - var tagDirective = _tagDirectives[tagToken.handle]; + var tagDirective = _tagDirectives[tagToken!.handle]; if (tagDirective == null) { - throw YamlException('Undefined tag handle.', tagToken.span); + throw YamlException('Undefined tag handle.', tagToken!.span); } - tag = tagDirective.prefix + tagToken.suffix; + tag = tagDirective.prefix + tagToken!.suffix; } } @@ -345,11 +345,11 @@ class Parser { /// BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END /// ******************** *********** * ********* Event _parseBlockSequenceEntry() { - var token = _scanner.peek(); + var token = _scanner.peek()!; if (token.type == TokenType.blockEntry) { var start = token.span.start; - token = _scanner.advance(); + token = _scanner.advance()!; if (token.type == TokenType.blockEntry || token.type == TokenType.blockEnd) { @@ -376,7 +376,7 @@ class Parser { /// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ /// *********** * Event _parseIndentlessSequenceEntry() { - var token = _scanner.peek(); + var token = _scanner.peek()!; if (token.type != TokenType.blockEntry) { _state = _states.removeLast(); @@ -384,7 +384,7 @@ class Parser { } var start = token.span.start; - token = _scanner.advance(); + token = _scanner.advance()!; if (token.type == TokenType.blockEntry || token.type == TokenType.key || @@ -409,10 +409,10 @@ class Parser { /// BLOCK-END /// ********* Event _parseBlockMappingKey() { - var token = _scanner.peek(); + var token = _scanner.peek()!; if (token.type == TokenType.key) { var start = token.span.start; - token = _scanner.advance(); + token = _scanner.advance()!; if (token.type == TokenType.key || token.type == TokenType.value || @@ -454,7 +454,7 @@ class Parser { /// BLOCK-END /// Event _parseBlockMappingValue() { - var token = _scanner.peek(); + var token = _scanner.peek()!; if (token.type != TokenType.value) { _state = _State.BLOCK_MAPPING_KEY; @@ -462,7 +462,7 @@ class Parser { } var start = token.span.start; - token = _scanner.advance(); + token = _scanner.advance()!; if (token.type == TokenType.key || token.type == TokenType.value || token.type == TokenType.blockEnd) { @@ -489,7 +489,7 @@ class Parser { /// * Event _parseFlowSequenceEntry({bool first = false}) { if (first) _scanner.scan(); - var token = _scanner.peek(); + var token = _scanner.peek()!; if (token.type != TokenType.flowSequenceEnd) { if (!first) { @@ -499,7 +499,7 @@ class Parser { token.span.start.pointSpan()); } - token = _scanner.advance(); + token = _scanner.advance()!; } if (token.type == TokenType.key) { @@ -523,7 +523,7 @@ class Parser { /// flow_node | KEY flow_node? (VALUE flow_node?)? /// *** * Event _parseFlowSequenceEntryMappingKey() { - var token = _scanner.peek(); + var token = _scanner.peek()!; if (token.type == TokenType.value || token.type == TokenType.flowEntry || @@ -547,10 +547,10 @@ class Parser { /// flow_node | KEY flow_node? (VALUE flow_node?)? /// ***** * Event _parseFlowSequenceEntryMappingValue() { - var token = _scanner.peek(); + var token = _scanner.peek()!; if (token.type == TokenType.value) { - token = _scanner.advance(); + token = _scanner.advance()!; if (token.type != TokenType.flowEntry && token.type != TokenType.flowSequenceEnd) { _states.add(_State.FLOW_SEQUENCE_ENTRY_MAPPING_END); @@ -569,7 +569,7 @@ class Parser { /// * Event _parseFlowSequenceEntryMappingEnd() { _state = _State.FLOW_SEQUENCE_ENTRY; - return Event(EventType.mappingEnd, _scanner.peek().span.start.pointSpan()); + return Event(EventType.mappingEnd, _scanner.peek()!.span.start.pointSpan()); } /// Parses the productions: @@ -587,7 +587,7 @@ class Parser { /// * *** * Event _parseFlowMappingKey({bool first = false}) { if (first) _scanner.scan(); - var token = _scanner.peek(); + var token = _scanner.peek()!; if (token.type != TokenType.flowMappingEnd) { if (!first) { @@ -597,11 +597,11 @@ class Parser { token.span.start.pointSpan()); } - token = _scanner.advance(); + token = _scanner.advance()!; } if (token.type == TokenType.key) { - token = _scanner.advance(); + token = _scanner.advance()!; if (token.type != TokenType.value && token.type != TokenType.flowEntry && token.type != TokenType.flowMappingEnd) { @@ -628,7 +628,7 @@ class Parser { /// flow_node | KEY flow_node? (VALUE flow_node?)? /// * ***** * Event _parseFlowMappingValue({bool empty = false}) { - var token = _scanner.peek(); + var token = _scanner.peek()!; if (empty) { _state = _State.FLOW_MAPPING_KEY; @@ -636,7 +636,7 @@ class Parser { } if (token.type == TokenType.value) { - token = _scanner.advance(); + token = _scanner.advance()!; if (token.type != TokenType.flowEntry && token.type != TokenType.flowMappingEnd) { _states.add(_State.FLOW_MAPPING_KEY); @@ -654,9 +654,9 @@ class Parser { /// Parses directives. Pair> _processDirectives() { - var token = _scanner.peek(); + var token = _scanner.peek()!; - VersionDirective versionDirective; + VersionDirective? versionDirective; var tagDirectives = []; while (token.type == TokenType.versionDirective || token.type == TokenType.tagDirective) { @@ -684,7 +684,7 @@ class Parser { tagDirectives.add(tagDirective); } - token = _scanner.advance(); + token = _scanner.advance()!; } _appendTagDirective(TagDirective('!', '!'), token.span.start.pointSpan(), diff --git a/lib/src/scanner.dart b/lib/src/scanner.dart index 98d54dfa2956f..fac955040759e 100644 --- a/lib/src/scanner.dart +++ b/lib/src/scanner.dart @@ -139,7 +139,7 @@ class Scanner { /// When a ":" is parsed and there's a simple key available, a [TokenType.key] /// token is inserted in [_tokens] before that key's token. This allows the /// parser to tell that the key is intended to be a mapping key. - final _simpleKeys = <_SimpleKey>[null]; + final _simpleKeys = <_SimpleKey?>[null]; /// The current indentation level. int get _indent => _indents.last; @@ -306,13 +306,13 @@ class Scanner { } /// Consumes the next token and returns the one after that. - Token advance() { + Token? advance() { scan(); return peek(); } /// Returns the next token without consuming it. - Token peek() { + Token? peek() { if (_streamEndProduced) return null; if (!_tokenAvailable) _fetchMoreTokens(); return _tokens.first; @@ -548,7 +548,7 @@ class Scanner { /// [tokenNumber] is provided, the corresponding token will be replaced; /// otherwise, the token will be added at the end. void _rollIndent(int column, TokenType type, SourceLocation location, - {int tokenNumber}) { + {int? tokenNumber}) { if (!_inBlockContext) return; if (_indent != -1 && _indent >= column) return; @@ -822,7 +822,7 @@ class Scanner { /// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /// %TAG !yaml! tag:yaml.org,2002: \n /// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Token _scanDirective() { + Token? _scanDirective() { var start = _scanner.state; // Eat '%'. @@ -979,7 +979,7 @@ class Scanner { /// Scans a [TokenType.tag] token. Token _scanTag() { - String handle; + String? handle; String suffix; var start = _scanner.state; @@ -1052,14 +1052,14 @@ class Scanner { /// [head] is the initial portion of the tag that's already been scanned. /// [flowSeparators] indicates whether the tag URI can contain flow /// separators. - String _scanTagUri({String head, bool flowSeparators = true}) { + String _scanTagUri({String? head, bool flowSeparators = true}) { var length = head == null ? 0 : head.length; var buffer = StringBuffer(); // Copy the head if needed. // // Note that we don't copy the leading '!' character. - if (length > 1) buffer.write(head.substring(1)); + if (length > 1) buffer.write(head!.substring(1)); // The set of characters that may appear in URI is as follows: // @@ -1146,8 +1146,8 @@ class Scanner { // Scan the leading line breaks to determine the indentation level if // needed. var pair = _scanBlockScalarBreaks(indent); - indent = pair.first; - var trailingBreaks = pair.last; + indent = pair.first!; + var trailingBreaks = pair.last!; // Scan the block scalar contents. var buffer = StringBuffer(); @@ -1198,8 +1198,8 @@ class Scanner { // Eat the following indentation and spaces. var pair = _scanBlockScalarBreaks(indent); - indent = pair.first; - trailingBreaks = pair.last; + indent = pair.first!; + trailingBreaks = pair.last!; } // Chomp the tail. @@ -1287,7 +1287,7 @@ class Scanner { var escapeStart = _scanner.state; // An escape sequence. - int codeLength; + int? codeLength; switch (_scanner.peekChar(1)) { case NUMBER_0: buffer.writeCharCode(NULL); @@ -1324,7 +1324,7 @@ class Scanner { // libyaml doesn't support an escaped forward slash, but it was // added in YAML 1.2. See section 5.7: // http://yaml.org/spec/1.2/spec.html#id2776092 - buffer.writeCharCode(_scanner.peekChar(1)); + buffer.writeCharCode(_scanner.peekChar(1)!); break; case LETTER_CAP_N: buffer.writeCharCode(NEL); @@ -1658,7 +1658,7 @@ class _SimpleKey { final bool required; _SimpleKey(this.tokenNumber, this.line, this.column, this.location, - {bool required}) + {required bool required}) : required = required; } diff --git a/lib/src/token.dart b/lib/src/token.dart index 84165545fe8e5..7dbfb3bdea712 100644 --- a/lib/src/token.dart +++ b/lib/src/token.dart @@ -93,7 +93,7 @@ class TagToken implements Token { final FileSpan span; /// The tag handle for named tags. - final String handle; + final String? handle; /// The tag suffix, or `null`. final String suffix; @@ -127,26 +127,21 @@ class ScalarToken implements Token { enum TokenType { streamStart, streamEnd, - versionDirective, tagDirective, documentStart, documentEnd, - blockSequenceStart, blockMappingStart, blockEnd, - flowSequenceStart, flowSequenceEnd, flowMappingStart, flowMappingEnd, - blockEntry, flowEntry, key, value, - alias, anchor, tag, diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 8ce7855019bd2..20210ef1ad21e 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -6,8 +6,8 @@ import 'package:source_span/source_span.dart'; /// A pair of values. class Pair { - final E first; - final F last; + final E? first; + final F? last; Pair(this.first, this.last); @@ -18,7 +18,7 @@ class Pair { /// Print a warning. /// /// If [span] is passed, associates the warning with that span. -void warn(String message, [SourceSpan span]) => +void warn(String message, [SourceSpan? span]) => yamlWarningCallback(message, span); /// A callback for emitting a warning. @@ -26,14 +26,14 @@ void warn(String message, [SourceSpan span]) => /// [message] is the text of the warning. If [span] is passed, it's the portion /// of the document that the warning is associated with and should be included /// in the printed warning. -typedef YamlWarningCallback = Function(String message, [SourceSpan span]); +typedef YamlWarningCallback = Function(String message, [SourceSpan? span]); /// A callback for emitting a warning. /// /// In a very few cases, the YAML spec indicates that an implementation should /// emit a warning. To do so, it calls this callback. The default implementation /// prints a message using [print]. -YamlWarningCallback yamlWarningCallback = (message, [span]) { +YamlWarningCallback yamlWarningCallback = (message, [SourceSpan? span]) { // TODO(nweiz): Print to stderr with color when issue 6943 is fixed and // dart:io is available. if (span != null) message = span.message(message); diff --git a/lib/src/yaml_document.dart b/lib/src/yaml_document.dart index 8757418ad4835..65b9548dff4f7 100644 --- a/lib/src/yaml_document.dart +++ b/lib/src/yaml_document.dart @@ -17,7 +17,7 @@ class YamlDocument { final SourceSpan span; /// The version directive for the document, if any. - final VersionDirective versionDirective; + final VersionDirective? versionDirective; /// The tag directives for the document. final List tagDirectives; diff --git a/lib/src/yaml_exception.dart b/lib/src/yaml_exception.dart index c4b7f28b851af..1941f0238e883 100644 --- a/lib/src/yaml_exception.dart +++ b/lib/src/yaml_exception.dart @@ -6,5 +6,5 @@ import 'package:source_span/source_span.dart'; /// An error thrown by the YAML processor. class YamlException extends SourceSpanFormatException { - YamlException(String message, SourceSpan span) : super(message, span); + YamlException(String message, SourceSpan? span) : super(message, span); } diff --git a/lib/src/yaml_node.dart b/lib/src/yaml_node.dart index bbba77e259fd0..c8f294b4b646a 100644 --- a/lib/src/yaml_node.dart +++ b/lib/src/yaml_node.dart @@ -26,9 +26,9 @@ abstract class YamlNode { /// /// [SourceSpan.message] can be used to produce a human-friendly message about /// this node. - SourceSpan get span => _span; + SourceSpan? get span => _span; - SourceSpan _span; + SourceSpan? _span; /// The inner value of this node. /// diff --git a/lib/src/yaml_node_wrapper.dart b/lib/src/yaml_node_wrapper.dart index 1e44a09e255c7..87328ba1c6694 100644 --- a/lib/src/yaml_node_wrapper.dart +++ b/lib/src/yaml_node_wrapper.dart @@ -45,7 +45,7 @@ class YamlMapWrapper extends MapBase } @override - dynamic operator [](Object key) { + dynamic operator [](Object? key) { var value = _dartMap[key]; if (value is Map) return YamlMapWrapper._(value, span); if (value is List) return YamlListWrapper._(value, span); @@ -75,9 +75,9 @@ class _YamlMapNodes extends MapBase _YamlMapNodes(this._dartMap, this._span); @override - YamlNode operator [](Object key) { + YamlNode? operator [](Object? key) { // Use "as" here because key being assigned to invalidates type propagation. - if (key is YamlScalar) key = (key as YamlScalar).value; + if (key is YamlScalar) key = key.value; if (!_dartMap.containsKey(key)) return null; return _nodeForValue(_dartMap[key], _span); } diff --git a/pubspec.yaml b/pubspec.yaml index 31e50012d7cd2..2c3215f9ca802 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,19 +1,19 @@ name: yaml -version: 2.3.0-dev +version: 2.3.0-nullsafety description: A parser for YAML, a human-friendly data serialization standard homepage: https://github.com/dart-lang/yaml environment: - sdk: ">=2.4.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' dependencies: charcode: ^1.1.0 - collection: ">=1.1.0 <2.0.0" - string_scanner: ">=0.1.4 <2.0.0" - source_span: ">=1.0.0 <2.0.0" + collection: ^1.15.0-nullsafety + string_scanner: ^1.1.0-nullsafety + source_span: ^1.8.0-nullsafety dev_dependencies: - pedantic: ^1.0.0 - path: ">=1.2.0 <2.0.0" - test: ">=0.12.0 <2.0.0" + pedantic: ^1.10.0-nullsafety + path: ^1.8.0-nullsafety + test: ^1.16.0-nullsafety diff --git a/test/span_test.dart b/test/span_test.dart index 4017868254895..6c666dd774d3e 100644 --- a/test/span_test.dart +++ b/test/span_test.dart @@ -8,15 +8,15 @@ import 'package:source_span/source_span.dart'; import 'package:test/test.dart'; import 'package:yaml/yaml.dart'; -void _expectSpan(SourceSpan source, String expected) { - final result = source.message('message'); +void _expectSpan(SourceSpan? source, String expected) { + final result = source!.message('message'); printOnFailure("r'''\n$result'''"); expect(result, expected); } void main() { - YamlMap yaml; + late YamlMap yaml; setUpAll(() { yaml = loadYaml(const JsonEncoder.withIndent(' ').convert({ @@ -31,7 +31,7 @@ void main() { test('first root key', () { _expectSpan( - yaml.nodes['num'].span, + yaml.nodes['num']!.span, r''' line 2, column 9: message ╷ @@ -43,7 +43,7 @@ line 2, column 9: message test('first root key', () { _expectSpan( - yaml.nodes['null'].span, + yaml.nodes['null']!.span, r''' line 7, column 10: message ╷ @@ -54,7 +54,7 @@ line 7, column 10: message }); group('nested', () { - YamlMap nestedMap; + late YamlMap nestedMap; setUpAll(() { nestedMap = yaml.nodes['nested'] as YamlMap; @@ -62,7 +62,7 @@ line 7, column 10: message test('first root key', () { _expectSpan( - nestedMap.nodes['null'].span, + nestedMap.nodes['null']!.span, r''' line 4, column 11: message ╷ @@ -74,7 +74,7 @@ line 4, column 11: message test('first root key', () { _expectSpan( - nestedMap.nodes['num'].span, + nestedMap.nodes['num']!.span, r''' line 5, column 10: message ╷ @@ -88,7 +88,7 @@ line 5, column 10: message }); group('block', () { - YamlList list, nestedList; + late YamlList list, nestedList; setUpAll(() { const yamlStr = ''' diff --git a/test/utils.dart b/test/utils.dart index c49afe2d3fdb1..ce05481421bea 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -16,7 +16,7 @@ Matcher deepEquals(expected) => predicate( (actual) => equality.deepEquals(actual, expected), 'equals $expected'); /// Constructs a new yaml.YamlMap, optionally from a normal Map. -Map deepEqualsMap([Map from]) { +Map deepEqualsMap([Map? from]) { var map = equality.deepEqualsMap(); if (from != null) map.addAll(from); return map; diff --git a/test/yaml_node_wrapper_test.dart b/test/yaml_node_wrapper_test.dart index d6da052059590..e5d71cc540361 100644 --- a/test/yaml_node_wrapper_test.dart +++ b/test/yaml_node_wrapper_test.dart @@ -61,8 +61,8 @@ void main() { expect(map['map']['nested'], TypeMatcher()); expect(map['map'].span, isNullSpan(isNull)); expect(map.nodes['scalar'], TypeMatcher()); - expect(map.nodes['scalar'].value, 'value'); - expect(map.nodes['scalar'].span, isNullSpan(isNull)); + expect(map.nodes['scalar']!.value, 'value'); + expect(map.nodes['scalar']!.span, isNullSpan(isNull)); expect(map['scalar'], 'value'); expect(map.keys, unorderedEquals(['list', 'map', 'scalar'])); expect(map.nodes.keys, everyElement(TypeMatcher())); @@ -88,7 +88,7 @@ void main() { expect(map.span, isNullSpan(source)); expect(map['list'].span, isNullSpan(source)); expect(map['map'].span, isNullSpan(source)); - expect(map.nodes['scalar'].span, isNullSpan(source)); + expect(map.nodes['scalar']!.span, isNullSpan(source)); }); test('YamlMap.wrap() with a sourceUrl and style', () { @@ -217,7 +217,7 @@ void main() { }); } -Matcher isNullSpan(sourceUrl) => predicate((span) { +Matcher isNullSpan(sourceUrl) => predicate((SourceSpan span) { expect(span, TypeMatcher()); expect(span.length, equals(0)); expect(span.text, isEmpty); diff --git a/test/yaml_test.dart b/test/yaml_test.dart index a0fb8f1108c2d..3633a5e189a57 100644 --- a/test/yaml_test.dart +++ b/test/yaml_test.dart @@ -68,16 +68,16 @@ void main() { - 123 ''') as YamlList; - expect(yaml.span.start.line, equals(0)); - expect(yaml.span.start.column, equals(0)); - expect(yaml.span.end.line, equals(3)); - expect(yaml.span.end.column, equals(0)); + expect(yaml.span!.start.line, equals(0)); + expect(yaml.span!.start.column, equals(0)); + expect(yaml.span!.end.line, equals(3)); + expect(yaml.span!.end.column, equals(0)); var map = yaml.nodes.first as YamlMap; - expect(map.span.start.line, equals(0)); - expect(map.span.start.column, equals(2)); - expect(map.span.end.line, equals(2)); - expect(map.span.end.column, equals(0)); + expect(map.span!.start.line, equals(0)); + expect(map.span!.start.column, equals(2)); + expect(map.span!.end.line, equals(2)); + expect(map.span!.end.column, equals(0)); var key = map.nodes.keys.first; expect(key.span.start.line, equals(0)); @@ -86,16 +86,16 @@ void main() { expect(key.span.end.column, equals(5)); var value = map.nodes.values.first; - expect(value.span.start.line, equals(1)); - expect(value.span.start.column, equals(4)); - expect(value.span.end.line, equals(1)); - expect(value.span.end.column, equals(7)); + expect(value.span!.start.line, equals(1)); + expect(value.span!.start.column, equals(4)); + expect(value.span!.end.line, equals(1)); + expect(value.span!.end.column, equals(7)); var scalar = yaml.nodes.last; - expect(scalar.span.start.line, equals(2)); - expect(scalar.span.start.column, equals(2)); - expect(scalar.span.end.line, equals(2)); - expect(scalar.span.end.column, equals(5)); + expect(scalar.span!.start.line, equals(2)); + expect(scalar.span!.start.column, equals(2)); + expect(scalar.span!.end.line, equals(2)); + expect(scalar.span!.end.column, equals(5)); }); // The following tests are all taken directly from the YAML spec From 0078ffe926bacc874bcfb920d9be8c40cbc4b085 Mon Sep 17 00:00:00 2001 From: pq Date: Fri, 6 Nov 2020 22:09:55 -0800 Subject: [PATCH 02/15] unconstrain dart --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e982192b6707c..e0a5b905b1821 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: dart dart: - - 2.4.0 - dev dart_task: From 8b68d3c1a7e69601f65e8378f6a4773a7e32c870 Mon Sep 17 00:00:00 2001 From: pq Date: Fri, 6 Nov 2020 22:12:40 -0800 Subject: [PATCH 03/15] updated charcode dep --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 2c3215f9ca802..b78a39baec0dc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,7 +8,7 @@ environment: sdk: '>=2.12.0-0 <3.0.0' dependencies: - charcode: ^1.1.0 + charcode: ^1.2.0-nullsafety collection: ^1.15.0-nullsafety string_scanner: ^1.1.0-nullsafety source_span: ^1.8.0-nullsafety From d764444fdc32f07194368fe3ed8911de32db66fc Mon Sep 17 00:00:00 2001 From: pq Date: Fri, 6 Nov 2020 22:16:12 -0800 Subject: [PATCH 04/15] sort --- pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index b78a39baec0dc..435655e37c548 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,10 +10,10 @@ environment: dependencies: charcode: ^1.2.0-nullsafety collection: ^1.15.0-nullsafety - string_scanner: ^1.1.0-nullsafety source_span: ^1.8.0-nullsafety + string_scanner: ^1.1.0-nullsafety dev_dependencies: - pedantic: ^1.10.0-nullsafety path: ^1.8.0-nullsafety + pedantic: ^1.10.0-nullsafety test: ^1.16.0-nullsafety From 2b74c8335e56a77cd35229ed201dbc9ebb9e27af Mon Sep 17 00:00:00 2001 From: pq Date: Mon, 9 Nov 2020 09:35:43 -0800 Subject: [PATCH 05/15] updated version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 435655e37c548..9b5b56855ef43 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: yaml -version: 2.3.0-nullsafety +version: 2.3.0-nullsafety.0 description: A parser for YAML, a human-friendly data serialization standard homepage: https://github.com/dart-lang/yaml From 379220c1b03d99c89fb466e1dbe81f7626a91136 Mon Sep 17 00:00:00 2001 From: pq Date: Mon, 9 Nov 2020 09:54:12 -0800 Subject: [PATCH 06/15] fixed ws --- lib/src/null_span.dart | 1 - lib/src/token.dart | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/src/null_span.dart b/lib/src/null_span.dart index dd868b808fb5a..64b3551ed79f0 100644 --- a/lib/src/null_span.dart +++ b/lib/src/null_span.dart @@ -12,7 +12,6 @@ import 'package:source_span/source_span.dart'; class NullSpan extends SourceSpanMixin { @override final SourceLocation start; - @override SourceLocation get end => start; @override diff --git a/lib/src/token.dart b/lib/src/token.dart index 7dbfb3bdea712..4f4172f261bd4 100644 --- a/lib/src/token.dart +++ b/lib/src/token.dart @@ -127,21 +127,26 @@ class ScalarToken implements Token { enum TokenType { streamStart, streamEnd, + versionDirective, tagDirective, documentStart, documentEnd, + blockSequenceStart, blockMappingStart, blockEnd, + flowSequenceStart, flowSequenceEnd, flowMappingStart, flowMappingEnd, + blockEntry, flowEntry, key, value, + alias, anchor, tag, From b5487ec603b266f9d73f95fd426c137cc2a30979 Mon Sep 17 00:00:00 2001 From: pq Date: Mon, 9 Nov 2020 09:59:06 -0800 Subject: [PATCH 07/15] made suffix nullable --- lib/src/parser.dart | 2 +- lib/src/token.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/parser.dart b/lib/src/parser.dart index 267d7cadf7430..0f824be696b92 100644 --- a/lib/src/parser.dart +++ b/lib/src/parser.dart @@ -287,7 +287,7 @@ class Parser { throw YamlException('Undefined tag handle.', tagToken!.span); } - tag = tagDirective.prefix + tagToken!.suffix; + tag = tagDirective.prefix + (tagToken?.suffix ?? ''); } } diff --git a/lib/src/token.dart b/lib/src/token.dart index 4f4172f261bd4..447e979d78339 100644 --- a/lib/src/token.dart +++ b/lib/src/token.dart @@ -96,7 +96,7 @@ class TagToken implements Token { final String? handle; /// The tag suffix, or `null`. - final String suffix; + final String? suffix; TagToken(this.span, this.handle, this.suffix); From b6c574d71dd8c32db5aa5d0d06b4813457e0e81a Mon Sep 17 00:00:00 2001 From: pq Date: Mon, 9 Nov 2020 10:35:30 -0800 Subject: [PATCH 08/15] + notes --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f633990d3bed..bf281c5e5211d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ -## 2.3.0-dev - +## 2.3.0-nullsafety +* Updated to support 2.12.0 and null safety. * Allow `YamlNode`s to be wrapped with an optional `style` parameter. ## 2.2.1 From bc76bb58a7f46fc60df7431ba5956c6b71404845 Mon Sep 17 00:00:00 2001 From: pq Date: Mon, 9 Nov 2020 14:33:59 -0800 Subject: [PATCH 09/15] bumped major version --- CHANGELOG.md | 2 +- pubspec.yaml | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf281c5e5211d..1cb12d6ad5b53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.3.0-nullsafety +## 3.0.0-nullsafety * Updated to support 2.12.0 and null safety. * Allow `YamlNode`s to be wrapped with an optional `style` parameter. diff --git a/pubspec.yaml b/pubspec.yaml index 9b5b56855ef43..10d100422326e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: yaml -version: 2.3.0-nullsafety.0 +version: 3.0.0-nullsafety.0 description: A parser for YAML, a human-friendly data serialization standard homepage: https://github.com/dart-lang/yaml @@ -17,3 +17,9 @@ dev_dependencies: path: ^1.8.0-nullsafety pedantic: ^1.10.0-nullsafety test: ^1.16.0-nullsafety + +dependency_overrides: + analyzer: ^0.40.0 + test: ^1.16.0-nullsafety + test_api: ^0.2.19-nullsafety + test_core: ^0.3.12-nullsafety From 7e97ddfa6da67f6ca15939fb48a7953bde2425a1 Mon Sep 17 00:00:00 2001 From: pq Date: Mon, 9 Nov 2020 14:39:12 -0800 Subject: [PATCH 10/15] fix suffix --- lib/src/token.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/token.dart b/lib/src/token.dart index 447e979d78339..711950c57f7c7 100644 --- a/lib/src/token.dart +++ b/lib/src/token.dart @@ -95,8 +95,8 @@ class TagToken implements Token { /// The tag handle for named tags. final String? handle; - /// The tag suffix, or `null`. - final String? suffix; + /// The tag suffix. + final String suffix; TagToken(this.span, this.handle, this.suffix); From 38004bcd3b3f7f6af844a15ee74416c7f32a4e4c Mon Sep 17 00:00:00 2001 From: pq Date: Mon, 9 Nov 2020 14:42:53 -0800 Subject: [PATCH 11/15] fixed pair API --- lib/src/parser.dart | 2 +- lib/src/scanner.dart | 8 ++++---- lib/src/utils.dart | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/src/parser.dart b/lib/src/parser.dart index 0f824be696b92..625abe6b8efe0 100644 --- a/lib/src/parser.dart +++ b/lib/src/parser.dart @@ -653,7 +653,7 @@ class Parser { ScalarEvent(location.pointSpan() as FileSpan, '', ScalarStyle.PLAIN); /// Parses directives. - Pair> _processDirectives() { + Pair> _processDirectives() { var token = _scanner.peek()!; VersionDirective? versionDirective; diff --git a/lib/src/scanner.dart b/lib/src/scanner.dart index fac955040759e..942e5782af403 100644 --- a/lib/src/scanner.dart +++ b/lib/src/scanner.dart @@ -1146,8 +1146,8 @@ class Scanner { // Scan the leading line breaks to determine the indentation level if // needed. var pair = _scanBlockScalarBreaks(indent); - indent = pair.first!; - var trailingBreaks = pair.last!; + indent = pair.first; + var trailingBreaks = pair.last; // Scan the block scalar contents. var buffer = StringBuffer(); @@ -1198,8 +1198,8 @@ class Scanner { // Eat the following indentation and spaces. var pair = _scanBlockScalarBreaks(indent); - indent = pair.first!; - trailingBreaks = pair.last!; + indent = pair.first; + trailingBreaks = pair.last; } // Chomp the tail. diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 20210ef1ad21e..2c69eade414a6 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -6,8 +6,8 @@ import 'package:source_span/source_span.dart'; /// A pair of values. class Pair { - final E? first; - final F? last; + final E first; + final F last; Pair(this.first, this.last); From 48089dfceb4ef2e4917b92b89b9a40ceeab357bf Mon Sep 17 00:00:00 2001 From: pq Date: Mon, 9 Nov 2020 14:50:54 -0800 Subject: [PATCH 12/15] make span non-nullable --- lib/src/yaml_node.dart | 4 ++-- test/yaml_test.dart | 32 ++++++++++++++++---------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/src/yaml_node.dart b/lib/src/yaml_node.dart index c8f294b4b646a..a02ea0f69c494 100644 --- a/lib/src/yaml_node.dart +++ b/lib/src/yaml_node.dart @@ -26,9 +26,9 @@ abstract class YamlNode { /// /// [SourceSpan.message] can be used to produce a human-friendly message about /// this node. - SourceSpan? get span => _span; + SourceSpan get span => _span; - SourceSpan? _span; + late SourceSpan _span; /// The inner value of this node. /// diff --git a/test/yaml_test.dart b/test/yaml_test.dart index 3633a5e189a57..a0fb8f1108c2d 100644 --- a/test/yaml_test.dart +++ b/test/yaml_test.dart @@ -68,16 +68,16 @@ void main() { - 123 ''') as YamlList; - expect(yaml.span!.start.line, equals(0)); - expect(yaml.span!.start.column, equals(0)); - expect(yaml.span!.end.line, equals(3)); - expect(yaml.span!.end.column, equals(0)); + expect(yaml.span.start.line, equals(0)); + expect(yaml.span.start.column, equals(0)); + expect(yaml.span.end.line, equals(3)); + expect(yaml.span.end.column, equals(0)); var map = yaml.nodes.first as YamlMap; - expect(map.span!.start.line, equals(0)); - expect(map.span!.start.column, equals(2)); - expect(map.span!.end.line, equals(2)); - expect(map.span!.end.column, equals(0)); + expect(map.span.start.line, equals(0)); + expect(map.span.start.column, equals(2)); + expect(map.span.end.line, equals(2)); + expect(map.span.end.column, equals(0)); var key = map.nodes.keys.first; expect(key.span.start.line, equals(0)); @@ -86,16 +86,16 @@ void main() { expect(key.span.end.column, equals(5)); var value = map.nodes.values.first; - expect(value.span!.start.line, equals(1)); - expect(value.span!.start.column, equals(4)); - expect(value.span!.end.line, equals(1)); - expect(value.span!.end.column, equals(7)); + expect(value.span.start.line, equals(1)); + expect(value.span.start.column, equals(4)); + expect(value.span.end.line, equals(1)); + expect(value.span.end.column, equals(7)); var scalar = yaml.nodes.last; - expect(scalar.span!.start.line, equals(2)); - expect(scalar.span!.start.column, equals(2)); - expect(scalar.span!.end.line, equals(2)); - expect(scalar.span!.end.column, equals(5)); + expect(scalar.span.start.line, equals(2)); + expect(scalar.span.start.column, equals(2)); + expect(scalar.span.end.line, equals(2)); + expect(scalar.span.end.column, equals(5)); }); // The following tests are all taken directly from the YAML spec From 11d051475259020610d6debd10331046ed845450 Mon Sep 17 00:00:00 2001 From: pq Date: Mon, 9 Nov 2020 14:57:43 -0800 Subject: [PATCH 13/15] make sourcespan non-nullable --- test/span_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/span_test.dart b/test/span_test.dart index 6c666dd774d3e..b8170e655545e 100644 --- a/test/span_test.dart +++ b/test/span_test.dart @@ -8,8 +8,8 @@ import 'package:source_span/source_span.dart'; import 'package:test/test.dart'; import 'package:yaml/yaml.dart'; -void _expectSpan(SourceSpan? source, String expected) { - final result = source!.message('message'); +void _expectSpan(SourceSpan source, String expected) { + final result = source.message('message'); printOnFailure("r'''\n$result'''"); expect(result, expected); From 0cc0d90cd15c2629bad0df48a712cde01a9bf461 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Mon, 9 Nov 2020 15:16:32 -0800 Subject: [PATCH 14/15] Different pattern for _span so it doesn't need to be late Instead of marking the field nullable, or late, add a constructor in the abstract class and use it from the others. It was already impossible to correctly subclass `YamlNode` from outside the library, so the addition of a private constructor should not be breaking. --- lib/src/yaml_node.dart | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/src/yaml_node.dart b/lib/src/yaml_node.dart index a02ea0f69c494..3e3ae8d1cec4d 100644 --- a/lib/src/yaml_node.dart +++ b/lib/src/yaml_node.dart @@ -27,8 +27,9 @@ abstract class YamlNode { /// [SourceSpan.message] can be used to produce a human-friendly message about /// this node. SourceSpan get span => _span; + SourceSpan _span; - late SourceSpan _span; + YamlNode._(this._span); /// The inner value of this node. /// @@ -83,9 +84,8 @@ class YamlMap extends YamlNode with collection.MapMixin, UnmodifiableMapMixin { /// Users of the library should not use this constructor. YamlMap.internal(Map nodes, SourceSpan span, this.style) - : nodes = UnmodifiableMapView(nodes) { - _span = span; - } + : nodes = UnmodifiableMapView(nodes), + super._(span); @override dynamic operator [](key) => nodes[key]?.value; @@ -134,9 +134,8 @@ class YamlList extends YamlNode with collection.ListMixin { /// Users of the library should not use this constructor. YamlList.internal(List nodes, SourceSpan span, this.style) - : nodes = UnmodifiableListView(nodes) { - _span = span; - } + : nodes = UnmodifiableListView(nodes), + super._(span); @override dynamic operator [](int index) => nodes[index].value; @@ -162,21 +161,20 @@ class YamlScalar extends YamlNode { /// [sourceUrl] is passed, it's used as the [SourceSpan.sourceUrl]. /// /// [sourceUrl] may be either a [String], a [Uri], or `null`. - YamlScalar.wrap(this.value, {sourceUrl, this.style = ScalarStyle.ANY}) { + YamlScalar.wrap(this.value, {sourceUrl, this.style = ScalarStyle.ANY}) + : super._(NullSpan(sourceUrl)) { ArgumentError.checkNotNull(style, 'style'); - _span = NullSpan(sourceUrl); } /// Users of the library should not use this constructor. - YamlScalar.internal(this.value, ScalarEvent scalar) : style = scalar.style { - _span = scalar.span; - } + YamlScalar.internal(this.value, ScalarEvent scalar) + : style = scalar.style, + super._(scalar.span); /// Users of the library should not use this constructor. YamlScalar.internalWithSpan(this.value, SourceSpan span) - : style = ScalarStyle.ANY { - _span = span; - } + : style = ScalarStyle.ANY, + super._(span); @override String toString() => value.toString(); From 25628a5070a63c425f6f9f3e7cc709363d2a4fb2 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 10 Nov 2020 11:19:31 -0800 Subject: [PATCH 15/15] Avoid a late FileSpan field Split a constructor into a factory and generative constructor to avoid a late field. --- lib/src/loader.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/src/loader.dart b/lib/src/loader.dart index 370540609a98e..c60e6736c72be 100644 --- a/lib/src/loader.dart +++ b/lib/src/loader.dart @@ -27,18 +27,20 @@ class Loader { /// The span of the entire stream emitted so far. FileSpan get span => _span; - late FileSpan _span; + FileSpan _span; /// Creates a loader that loads [source]. /// /// [sourceUrl] can be a String or a [Uri]. - Loader(String source, {sourceUrl}) - : _parser = Parser(source, sourceUrl: sourceUrl) { - var event = _parser.parse(); - _span = event.span; + factory Loader(String source, {sourceUrl}) { + var parser = Parser(source, sourceUrl: sourceUrl); + var event = parser.parse(); assert(event.type == EventType.streamStart); + return Loader._(parser, event.span); } + Loader._(this._parser, this._span); + /// Loads the next document from the stream. /// /// If there are no more documents, returns `null`.