Attach source range information to parsed YAML nodes.
Also release yaml 1.0.0.
R=efortuna@google.com, rnystrom@google.com, sigmund@google.com
Review URL: https://codereview.chromium.org//302313007
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/yaml@36937 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkgs/yaml/CHANGELOG.md b/pkgs/yaml/CHANGELOG.md
index 3520d4c..4b243d8 100644
--- a/pkgs/yaml/CHANGELOG.md
+++ b/pkgs/yaml/CHANGELOG.md
@@ -1,3 +1,18 @@
+## 1.0.0
+
+* **Backwards incompatibility**: The data structures returned by `loadYaml` and
+ `loadYamlStream` are now immutable.
+
+* **Backwards incompatibility**: The interface of the `YamlMap` class has
+ changed substantially in numerous ways. External users may no longer construct
+ their own instances.
+
+* Maps and lists returned by `loadYaml` and `loadYamlStream` now contain
+ information about their source locations.
+
+* A new `loadYamlNode` function returns the source location of top-level scalars
+ as well.
+
## 0.10.0
* Improve error messages when a file fails to parse.
diff --git a/pkgs/yaml/lib/src/composer.dart b/pkgs/yaml/lib/src/composer.dart
index 3178096..4c19da1 100644
--- a/pkgs/yaml/lib/src/composer.dart
+++ b/pkgs/yaml/lib/src/composer.dart
@@ -4,6 +4,8 @@
library yaml.composer;
+import 'package:source_maps/source_maps.dart';
+
import 'model.dart';
import 'visitor.dart';
import 'yaml_exception.dart';
@@ -45,13 +47,13 @@
/// Currently this only supports the YAML core type schema.
Node visitScalar(ScalarNode scalar) {
if (scalar.tag.name == "!") {
- return setAnchor(scalar, parseString(scalar.content));
+ return setAnchor(scalar, parseString(scalar));
} else if (scalar.tag.name == "?") {
for (var fn in [parseNull, parseBool, parseInt, parseFloat]) {
- var result = fn(scalar.content);
+ var result = fn(scalar);
if (result != null) return result;
}
- return setAnchor(scalar, parseString(scalar.content));
+ return setAnchor(scalar, parseString(scalar));
}
var result = _parseByTag(scalar);
@@ -62,11 +64,11 @@
ScalarNode _parseByTag(ScalarNode scalar) {
switch (scalar.tag.name) {
- case "null": return parseNull(scalar.content);
- case "bool": return parseBool(scalar.content);
- case "int": return parseInt(scalar.content);
- case "float": return parseFloat(scalar.content);
- case "str": return parseString(scalar.content);
+ case "null": return parseNull(scalar);
+ case "bool": return parseBool(scalar);
+ case "int": return parseInt(scalar);
+ case "float": return parseFloat(scalar);
+ case "str": return parseString(scalar);
}
throw new YamlException('Undefined tag: ${scalar.tag}.');
}
@@ -78,7 +80,8 @@
throw new YamlException("Invalid tag for sequence: ${seq.tag}.");
}
- var result = setAnchor(seq, new SequenceNode(Tag.yaml('seq'), null));
+ var result = setAnchor(seq,
+ new SequenceNode(Tag.yaml('seq'), null, seq.span));
result.content = super.visitSequence(seq);
return result;
}
@@ -90,7 +93,8 @@
throw new YamlException("Invalid tag for mapping: ${map.tag}.");
}
- var result = setAnchor(map, new MappingNode(Tag.yaml('map'), null));
+ var result = setAnchor(map,
+ new MappingNode(Tag.yaml('map'), null, map.span));
result.content = super.visitMapping(map);
return result;
}
@@ -105,36 +109,40 @@
}
/// Parses a null scalar.
- ScalarNode parseNull(String content) {
- if (!new RegExp(r"^(null|Null|NULL|~|)$").hasMatch(content)) return null;
- return new ScalarNode(Tag.yaml("null"), value: null);
+ ScalarNode parseNull(ScalarNode scalar) {
+ if (new RegExp(r"^(null|Null|NULL|~|)$").hasMatch(scalar.content)) {
+ return new ScalarNode(Tag.yaml("null"), scalar.span, value: null);
+ } else {
+ return null;
+ }
}
/// Parses a boolean scalar.
- ScalarNode parseBool(String content) {
+ ScalarNode parseBool(ScalarNode scalar) {
var match = new RegExp(r"^(?:(true|True|TRUE)|(false|False|FALSE))$").
- firstMatch(content);
+ firstMatch(scalar.content);
if (match == null) return null;
- return new ScalarNode(Tag.yaml("bool"), value: match.group(1) != null);
+ return new ScalarNode(Tag.yaml("bool"), scalar.span,
+ value: match.group(1) != null);
}
/// Parses an integer scalar.
- ScalarNode parseInt(String content) {
- var match = new RegExp(r"^[-+]?[0-9]+$").firstMatch(content);
+ ScalarNode parseInt(ScalarNode scalar) {
+ var match = new RegExp(r"^[-+]?[0-9]+$").firstMatch(scalar.content);
if (match != null) {
- return new ScalarNode(Tag.yaml("int"),
+ return new ScalarNode(Tag.yaml("int"), scalar.span,
value: int.parse(match.group(0)));
}
- match = new RegExp(r"^0o([0-7]+)$").firstMatch(content);
+ match = new RegExp(r"^0o([0-7]+)$").firstMatch(scalar.content);
if (match != null) {
int n = int.parse(match.group(1), radix: 8);
- return new ScalarNode(Tag.yaml("int"), value: n);
+ return new ScalarNode(Tag.yaml("int"), scalar.span, value: n);
}
- match = new RegExp(r"^0x[0-9a-fA-F]+$").firstMatch(content);
+ match = new RegExp(r"^0x[0-9a-fA-F]+$").firstMatch(scalar.content);
if (match != null) {
- return new ScalarNode(Tag.yaml("int"),
+ return new ScalarNode(Tag.yaml("int"), scalar.span,
value: int.parse(match.group(0)));
}
@@ -142,33 +150,33 @@
}
/// Parses a floating-point scalar.
- ScalarNode parseFloat(String content) {
+ ScalarNode parseFloat(ScalarNode scalar) {
var match = new RegExp(
- r"^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$").
- firstMatch(content);
+ r"^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$").
+ firstMatch(scalar.content);
if (match != null) {
// YAML allows floats of the form "0.", but Dart does not. Fix up those
// floats by removing the trailing dot.
var matchStr = match.group(0).replaceAll(new RegExp(r"\.$"), "");
- return new ScalarNode(Tag.yaml("float"),
+ return new ScalarNode(Tag.yaml("float"), scalar.span,
value: double.parse(matchStr));
}
- match = new RegExp(r"^([+-]?)\.(inf|Inf|INF)$").firstMatch(content);
+ match = new RegExp(r"^([+-]?)\.(inf|Inf|INF)$").firstMatch(scalar.content);
if (match != null) {
var value = match.group(1) == "-" ? -double.INFINITY : double.INFINITY;
- return new ScalarNode(Tag.yaml("float"), value: value);
+ return new ScalarNode(Tag.yaml("float"), scalar.span, value: value);
}
- match = new RegExp(r"^\.(nan|NaN|NAN)$").firstMatch(content);
+ match = new RegExp(r"^\.(nan|NaN|NAN)$").firstMatch(scalar.content);
if (match != null) {
- return new ScalarNode(Tag.yaml("float"), value: double.NAN);
+ return new ScalarNode(Tag.yaml("float"), scalar.span, value: double.NAN);
}
return null;
}
/// Parses a string scalar.
- ScalarNode parseString(String content) =>
- new ScalarNode(Tag.yaml("str"), value: content);
+ ScalarNode parseString(ScalarNode scalar) =>
+ new ScalarNode(Tag.yaml("str"), scalar.span, value: scalar.content);
}
diff --git a/pkgs/yaml/lib/src/constructor.dart b/pkgs/yaml/lib/src/constructor.dart
index 116809d..a8224a4 100644
--- a/pkgs/yaml/lib/src/constructor.dart
+++ b/pkgs/yaml/lib/src/constructor.dart
@@ -4,9 +4,10 @@
library yaml.constructor;
+import 'equality.dart';
import 'model.dart';
import 'visitor.dart';
-import 'yaml_map.dart';
+import 'yaml_node.dart';
/// Takes a parsed and composed YAML document (what the spec calls the
/// "representation graph") and creates native Dart objects that represent that
@@ -16,43 +17,54 @@
final Node _root;
/// Map from anchor names to the most recent Dart node with that anchor.
- final _anchors = <String, dynamic>{};
+ final _anchors = <String, YamlNode>{};
Constructor(this._root);
/// Runs the Constructor to produce a Dart object.
- construct() => _root.visit(this);
+ YamlNode construct() => _root.visit(this);
/// Returns the value of a scalar.
- visitScalar(ScalarNode scalar) => scalar.value;
+ YamlScalar visitScalar(ScalarNode scalar) =>
+ new YamlScalar(scalar.value, scalar.span);
/// Converts a sequence into a List of Dart objects.
- visitSequence(SequenceNode seq) {
+ YamlList visitSequence(SequenceNode seq) {
var anchor = getAnchor(seq);
if (anchor != null) return anchor;
- var dartSeq = setAnchor(seq, []);
- dartSeq.addAll(super.visitSequence(seq));
+ var nodes = [];
+ var dartSeq = setAnchor(seq, new YamlList(nodes, seq.span));
+ nodes.addAll(super.visitSequence(seq));
return dartSeq;
}
- /// Converts a mapping into a Map of Dart objects.
- visitMapping(MappingNode map) {
+ /// Converts a mapping into a [Map] of Dart objects.
+ YamlMap visitMapping(MappingNode map) {
var anchor = getAnchor(map);
if (anchor != null) return anchor;
- var dartMap = setAnchor(map, new YamlMap());
- super.visitMapping(map).forEach((k, v) { dartMap[k] = v; });
+ var nodes = deepEqualsMap();
+ var dartMap = setAnchor(map, new YamlMap(nodes, map.span));
+ super.visitMapping(map).forEach((k, v) => nodes[k] = v);
return dartMap;
}
- /// Returns the Dart object that already represents [anchored], if such a
- /// thing exists.
- getAnchor(Node anchored) {
+ /// Returns a new Dart object wrapping the object that already represents
+ /// [anchored], if such a thing exists.
+ YamlNode getAnchor(Node anchored) {
if (anchored.anchor == null) return null;
- if (_anchors.containsKey(anchored.anchor)) return _anchors[anchored.anchor];
+ var value = _anchors[anchored.anchor];
+ if (vaule == null) return null;
+
+ // Re-wrap [value]'s contents so that it's associated with the span of the
+ // anchor rather than its original definition.
+ if (value is YamlMap) return new YamlMap(value.nodes, anchored.span);
+ if (value is YamlList) return new YamlList(value.nodes, anchored.span);
+ assert(value is YamlScalar);
+ return new YamlScalar(value.value, anchored.span);
}
/// Records that [value] is the Dart object representing [anchored].
- setAnchor(Node anchored, value) {
+ YamlNode setAnchor(Node anchored, YamlNode value) {
if (anchored.anchor == null) return value;
_anchors[anchored.anchor] = value;
return value;
diff --git a/pkgs/yaml/lib/src/deep_equals.dart b/pkgs/yaml/lib/src/deep_equals.dart
deleted file mode 100644
index 68fb236..0000000
--- a/pkgs/yaml/lib/src/deep_equals.dart
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library yaml.deep_equals;
-
-/// Returns whether two objects are structurally equivalent.
-///
-/// This considers `NaN` values to be equivalent. It also handles
-/// self-referential structures.
-bool deepEquals(obj1, obj2) => new _DeepEquals().equals(obj1, obj2);
-
-/// A class that provides access to the list of parent objects used for loop
-/// detection.
-class _DeepEquals {
- final _parents1 = [];
- final _parents2 = [];
-
- /// Returns whether [obj1] and [obj2] are structurally equivalent.
- bool equals(obj1, obj2) {
- // _parents1 and _parents2 are guaranteed to be the same size.
- for (var i = 0; i < _parents1.length; i++) {
- var loop1 = identical(obj1, _parents1[i]);
- var loop2 = identical(obj2, _parents2[i]);
- // If both structures loop in the same place, they're equal at that point
- // in the structure. If one loops and the other doesn't, they're not
- // equal.
- if (loop1 && loop2) return true;
- if (loop1 || loop2) return false;
- }
-
- _parents1.add(obj1);
- _parents2.add(obj2);
- try {
- if (obj1 is List && obj2 is List) {
- return _listEquals(obj1, obj2);
- } else if (obj1 is Map && obj2 is Map) {
- return _mapEquals(obj1, obj2);
- } else if (obj1 is num && obj2 is num) {
- return _numEquals(obj1, obj2);
- } else {
- return obj1 == obj2;
- }
- } finally {
- _parents1.removeLast();
- _parents2.removeLast();
- }
- }
-
- /// Returns whether [list1] and [list2] are structurally equal.
- bool _listEquals(List list1, List list2) {
- if (list1.length != list2.length) return false;
-
- for (var i = 0; i < list1.length; i++) {
- if (!equals(list1[i], list2[i])) return false;
- }
-
- return true;
- }
-
- /// Returns whether [map1] and [map2] are structurally equal.
- bool _mapEquals(Map map1, Map map2) {
- if (map1.length != map2.length) return false;
-
- for (var key in map1.keys) {
- if (!map2.containsKey(key)) return false;
- if (!equals(map1[key], map2[key])) return false;
- }
-
- return true;
- }
-
- /// Returns whether two numbers are equivalent.
- ///
- /// This differs from `n1 == n2` in that it considers `NaN` to be equal to
- /// itself.
- bool _numEquals(num n1, num n2) {
- if (n1.isNaN && n2.isNaN) return true;
- return n1 == n2;
- }
-}
diff --git a/pkgs/yaml/lib/src/equality.dart b/pkgs/yaml/lib/src/equality.dart
new file mode 100644
index 0000000..5408135
--- /dev/null
+++ b/pkgs/yaml/lib/src/equality.dart
@@ -0,0 +1,126 @@
+// 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 yaml.equality;
+
+import 'dart:collection';
+
+import 'package:collection/collection.dart';
+
+import 'yaml_node.dart';
+
+/// Returns a [Map] that compares its keys based on [deepEquals].
+Map deepEqualsMap() => new HashMap(equals: deepEquals, hashCode: deepHashCode);
+
+/// Returns whether two objects are structurally equivalent.
+///
+/// This considers `NaN` values to be equivalent, handles self-referential
+/// structures, and considers [YamlScalar]s to be equal to their values.
+bool deepEquals(obj1, obj2) => new _DeepEquals().equals(obj1, obj2);
+
+/// A class that provides access to the list of parent objects used for loop
+/// detection.
+class _DeepEquals {
+ final _parents1 = [];
+ final _parents2 = [];
+
+ /// Returns whether [obj1] and [obj2] are structurally equivalent.
+ bool equals(obj1, obj2) {
+ if (obj1 is YamlScalar) obj1 = obj1.value;
+ if (obj2 is YamlScalar) obj2 = obj2.value;
+
+ // _parents1 and _parents2 are guaranteed to be the same size.
+ for (var i = 0; i < _parents1.length; i++) {
+ var loop1 = identical(obj1, _parents1[i]);
+ var loop2 = identical(obj2, _parents2[i]);
+ // If both structures loop in the same place, they're equal at that point
+ // in the structure. If one loops and the other doesn't, they're not
+ // equal.
+ if (loop1 && loop2) return true;
+ if (loop1 || loop2) return false;
+ }
+
+ _parents1.add(obj1);
+ _parents2.add(obj2);
+ try {
+ if (obj1 is List && obj2 is List) {
+ return _listEquals(obj1, obj2);
+ } else if (obj1 is Map && obj2 is Map) {
+ return _mapEquals(obj1, obj2);
+ } else if (obj1 is num && obj2 is num) {
+ return _numEquals(obj1, obj2);
+ } else {
+ return obj1 == obj2;
+ }
+ } finally {
+ _parents1.removeLast();
+ _parents2.removeLast();
+ }
+ }
+
+ /// Returns whether [list1] and [list2] are structurally equal.
+ bool _listEquals(List list1, List list2) {
+ if (list1.length != list2.length) return false;
+
+ for (var i = 0; i < list1.length; i++) {
+ if (!equals(list1[i], list2[i])) return false;
+ }
+
+ return true;
+ }
+
+ /// Returns whether [map1] and [map2] are structurally equal.
+ bool _mapEquals(Map map1, Map map2) {
+ if (map1.length != map2.length) return false;
+
+ for (var key in map1.keys) {
+ if (!map2.containsKey(key)) return false;
+ if (!equals(map1[key], map2[key])) return false;
+ }
+
+ return true;
+ }
+
+ /// Returns whether two numbers are equivalent.
+ ///
+ /// This differs from `n1 == n2` in that it considers `NaN` to be equal to
+ /// itself.
+ bool _numEquals(num n1, num n2) {
+ if (n1.isNaN && n2.isNaN) return true;
+ return n1 == n2;
+ }
+}
+
+/// Returns a hash code for [obj] such that structurally equivalent objects
+/// will have the same hash code.
+///
+/// This supports deep equality for maps and lists, including those with
+/// self-referential structures, and returns the same hash code for
+/// [YamlScalar]s and their values.
+int deepHashCode(obj) {
+ var parents = [];
+
+ _deepHashCode(value) {
+ if (parents.any((parent) => identical(parent, value))) return -1;
+
+ parents.add(value);
+ try {
+ if (value is Map) {
+ var equality = const UnorderedIterableEquality();
+ return equality.hash(value.keys.map(_deepHashCode)) ^
+ equality.hash(value.values.map(_deepHashCode));
+ } else if (value is Iterable) {
+ return const IterableEquality().hash(value.map(deepHashCode));
+ } else if (value is YamlScalar) {
+ return value.value.hashCode;
+ } else {
+ return value.hashCode;
+ }
+ } finally {
+ parents.removeLast();
+ }
+ }
+
+ return _deepHashCode(obj);
+}
diff --git a/pkgs/yaml/lib/src/model.dart b/pkgs/yaml/lib/src/model.dart
index 564cac6..f0e839c 100644
--- a/pkgs/yaml/lib/src/model.dart
+++ b/pkgs/yaml/lib/src/model.dart
@@ -7,8 +7,10 @@
/// representation graph.
library yaml.model;
+import 'package:source_maps/source_maps.dart';
+
+import 'equality.dart';
import 'parser.dart';
-import 'utils.dart';
import 'visitor.dart';
import 'yaml_exception.dart';
@@ -80,14 +82,17 @@
/// Any YAML node can have an anchor associated with it.
String anchor;
- Node(this.tag, [this.anchor]);
+ /// The source span for this node.
+ Span span;
+
+ Node(this.tag, this.span, [this.anchor]);
bool operator ==(other) {
if (other is! Node) return false;
return tag == other.tag;
}
- int get hashCode => hashCodeFor([tag, anchor]);
+ int get hashCode => tag.hashCode ^ anchor.hashCode;
visit(Visitor v);
}
@@ -97,8 +102,8 @@
/// The nodes in the sequence.
List<Node> content;
- SequenceNode(String tagName, this.content)
- : super(new Tag.sequence(tagName));
+ SequenceNode(String tagName, this.content, Span span)
+ : super(new Tag.sequence(tagName), span);
/// Two sequences are equal if their tags and contents are equal.
bool operator ==(other) {
@@ -113,14 +118,15 @@
String toString() => '$tag [${content.map((e) => '$e').join(', ')}]';
- int get hashCode => super.hashCode ^ hashCodeFor(content);
+ int get hashCode => super.hashCode ^ deepHashCode(content);
visit(Visitor v) => v.visitSequence(this);
}
/// An alias node is a reference to an anchor.
class AliasNode extends Node {
- AliasNode(String anchor) : super(new Tag.scalar(Tag.yaml("str")), anchor);
+ AliasNode(String anchor, Span span)
+ : super(new Tag.scalar(Tag.yaml("str")), span, anchor);
visit(Visitor v) => v.visitAlias(this);
}
@@ -139,9 +145,9 @@
/// be specified for a newly-parsed scalar that hasn't yet been composed.
/// Value should be specified for a composed scalar, although `null` is a
/// valid value.
- ScalarNode(String tagName, {String content, this.value})
+ ScalarNode(String tagName, Span span, {String content, this.value})
: _content = content,
- super(new Tag.scalar(tagName));
+ super(new Tag.scalar(tagName), span);
/// Two scalars are equal if their string representations are equal.
bool operator ==(other) {
@@ -225,8 +231,8 @@
/// The node map.
Map<Node, Node> content;
- MappingNode(String tagName, this.content)
- : super(new Tag.mapping(tagName));
+ MappingNode(String tagName, this.content, Span span)
+ : super(new Tag.mapping(tagName), span);
/// Two mappings are equal if their tags and contents are equal.
bool operator ==(other) {
@@ -247,7 +253,7 @@
return '$tag {$strContent}';
}
- int get hashCode => super.hashCode ^ hashCodeFor(content);
+ int get hashCode => super.hashCode ^ deepHashCode(content);
visit(Visitor v) => v.visitMapping(this);
}
diff --git a/pkgs/yaml/lib/src/parser.dart b/pkgs/yaml/lib/src/parser.dart
index d203c32..98658e6 100644
--- a/pkgs/yaml/lib/src/parser.dart
+++ b/pkgs/yaml/lib/src/parser.dart
@@ -6,11 +6,13 @@
import 'dart:collection';
+import 'package:source_maps/source_maps.dart';
import 'package:string_scanner/string_scanner.dart';
+import 'equality.dart';
import 'model.dart';
+import 'utils.dart';
import 'yaml_exception.dart';
-import 'yaml_map.dart';
/// Translates a string of characters into a YAML serialization tree.
///
@@ -317,7 +319,7 @@
}
/// Adds a tag and an anchor to [node], if they're defined.
- Node addProps(Node node, _Pair<Tag, String> props) {
+ Node addProps(Node node, Pair<Tag, String> props) {
if (props == null || node == null) return node;
if (truth(props.first)) node.tag = props.first;
if (truth(props.last)) node.anchor = props.last;
@@ -325,10 +327,10 @@
}
/// Creates a MappingNode from [pairs].
- MappingNode map(List<_Pair<Node, Node>> pairs) {
+ MappingNode map(List<Pair<Node, Node>> pairs, Span span) {
var content = new Map<Node, Node>();
pairs.forEach((pair) => content[pair.first] = pair.last);
- return new MappingNode("?", content);
+ return new MappingNode("?", content, span);
}
/// Runs [fn] in a context named [name]. Used for error reporting.
@@ -759,7 +761,7 @@
bool l_directive() => false; // TODO(nweiz): implement
// 96
- _Pair<Tag, String> c_ns_properties(int indent, int ctx) {
+ Pair<Tag, String> c_ns_properties(int indent, int ctx) {
var tag, anchor;
tag = c_ns_tagProperty();
if (truth(tag)) {
@@ -767,7 +769,7 @@
if (!truth(s_separate(indent, ctx))) return null;
return c_ns_anchorProperty();
});
- return new _Pair<Tag, String>(tag, anchor);
+ return new Pair<Tag, String>(tag, anchor);
}
anchor = c_ns_anchorProperty();
@@ -776,7 +778,7 @@
if (!truth(s_separate(indent, ctx))) return null;
return c_ns_tagProperty();
});
- return new _Pair<Tag, String>(tag, anchor);
+ return new Pair<Tag, String>(tag, anchor);
}
return null;
@@ -797,13 +799,14 @@
// 104
Node c_ns_aliasNode() {
+ var start = _scanner.state;
if (!truth(c_indicator(C_ALIAS))) return null;
var name = expect(ns_anchorName(), 'anchor name');
- return new AliasNode(name);
+ return new AliasNode(name, _scanner.spanFrom(start));
}
// 105
- ScalarNode e_scalar() => new ScalarNode("?", content: "");
+ ScalarNode e_scalar() => new ScalarNode("?", _scanner.emptySpan, content: "");
// 106
ScalarNode e_node() => e_scalar();
@@ -820,10 +823,11 @@
// 109
Node c_doubleQuoted(int indent, int ctx) => context('string', () {
return transaction(() {
+ var start = _scanner.state;
if (!truth(c_indicator(C_DOUBLE_QUOTE))) return null;
var contents = nb_doubleText(indent, ctx);
if (!truth(c_indicator(C_DOUBLE_QUOTE))) return null;
- return new ScalarNode("!", content: contents);
+ return new ScalarNode("!", _scanner.spanFrom(start), content: contents);
});
});
@@ -908,10 +912,11 @@
// 120
Node c_singleQuoted(int indent, int ctx) => context('string', () {
return transaction(() {
+ var start = _scanner.state;
if (!truth(c_indicator(C_SINGLE_QUOTE))) return null;
var contents = nb_singleText(indent, ctx);
if (!truth(c_indicator(C_SINGLE_QUOTE))) return null;
- return new ScalarNode("!", content: contents);
+ return new ScalarNode("!", _scanner.spanFrom(start), content: contents);
});
});
@@ -1075,11 +1080,13 @@
// 137
SequenceNode c_flowSequence(int indent, int ctx) => transaction(() {
+ var start = _scanner.state;
if (!truth(c_indicator(C_SEQUENCE_START))) return null;
zeroOrOne(() => s_separate(indent, ctx));
var content = zeroOrOne(() => ns_s_flowSeqEntries(indent, inFlow(ctx)));
if (!truth(c_indicator(C_SEQUENCE_END))) return null;
- return new SequenceNode("?", new List<Node>.from(content));
+ return new SequenceNode("?", new List<Node>.from(content),
+ _scanner.spanFrom(start));
});
// 138
@@ -1108,17 +1115,18 @@
// 140
Node c_flowMapping(int indent, int ctx) {
+ var start = _scanner.state;
if (!truth(c_indicator(C_MAPPING_START))) return null;
zeroOrOne(() => s_separate(indent, ctx));
var content = zeroOrOne(() => ns_s_flowMapEntries(indent, inFlow(ctx)));
if (!truth(c_indicator(C_MAPPING_END))) return null;
- return new MappingNode("?", content);
+ return new MappingNode("?", content, _scanner.spanFrom(start));
}
// 141
- YamlMap ns_s_flowMapEntries(int indent, int ctx) {
+ Map ns_s_flowMapEntries(int indent, int ctx) {
var first = ns_flowMapEntry(indent, ctx);
- if (!truth(first)) return new YamlMap();
+ if (!truth(first)) return deepEqualsMap();
zeroOrOne(() => s_separate(indent, ctx));
var rest;
@@ -1127,7 +1135,7 @@
rest = ns_s_flowMapEntries(indent, ctx);
}
- if (rest == null) rest = new YamlMap();
+ if (rest == null) rest = deepEqualsMap();
// TODO(nweiz): Duplicate keys should be an error. This includes keys with
// different representations but the same value (e.g. 10 vs 0xa). To make
@@ -1139,7 +1147,7 @@
}
// 142
- _Pair<Node, Node> ns_flowMapEntry(int indent, int ctx) => or([
+ Pair<Node, Node> ns_flowMapEntry(int indent, int ctx) => or([
() => transaction(() {
if (!truth(c_indicator(C_MAPPING_KEY))) return false;
if (!truth(s_separate(indent, ctx))) return false;
@@ -1149,20 +1157,20 @@
]);
// 143
- _Pair<Node, Node> ns_flowMapExplicitEntry(int indent, int ctx) => or([
+ Pair<Node, Node> ns_flowMapExplicitEntry(int indent, int ctx) => or([
() => ns_flowMapImplicitEntry(indent, ctx),
- () => new _Pair<Node, Node>(e_node(), e_node())
+ () => new Pair<Node, Node>(e_node(), e_node())
]);
// 144
- _Pair<Node, Node> ns_flowMapImplicitEntry(int indent, int ctx) => or([
+ Pair<Node, Node> ns_flowMapImplicitEntry(int indent, int ctx) => or([
() => ns_flowMapYamlKeyEntry(indent, ctx),
() => c_ns_flowMapEmptyKeyEntry(indent, ctx),
() => c_ns_flowMapJsonKeyEntry(indent, ctx)
]);
// 145
- _Pair<Node, Node> ns_flowMapYamlKeyEntry(int indent, int ctx) {
+ Pair<Node, Node> ns_flowMapYamlKeyEntry(int indent, int ctx) {
var key = ns_flowYamlNode(indent, ctx);
if (!truth(key)) return null;
var value = or([
@@ -1172,14 +1180,14 @@
}),
e_node
]);
- return new _Pair<Node, Node>(key, value);
+ return new Pair<Node, Node>(key, value);
}
// 146
- _Pair<Node, Node> c_ns_flowMapEmptyKeyEntry(int indent, int ctx) {
+ Pair<Node, Node> c_ns_flowMapEmptyKeyEntry(int indent, int ctx) {
var value = c_ns_flowMapSeparateValue(indent, ctx);
if (!truth(value)) return null;
- return new _Pair<Node, Node>(e_node(), value);
+ return new Pair<Node, Node>(e_node(), value);
}
// 147
@@ -1197,7 +1205,7 @@
});
// 148
- _Pair<Node, Node> c_ns_flowMapJsonKeyEntry(int indent, int ctx) {
+ Pair<Node, Node> c_ns_flowMapJsonKeyEntry(int indent, int ctx) {
var key = c_flowJsonNode(indent, ctx);
if (!truth(key)) return null;
var value = or([
@@ -1207,7 +1215,7 @@
}),
e_node
]);
- return new _Pair<Node, Node>(key, value);
+ return new Pair<Node, Node>(key, value);
}
// 149
@@ -1224,6 +1232,7 @@
// 150
Node ns_flowPair(int indent, int ctx) {
+ var start = _scanner.state;
var pair = or([
() => transaction(() {
if (!truth(c_indicator(C_MAPPING_KEY))) return null;
@@ -1234,34 +1243,34 @@
]);
if (!truth(pair)) return null;
- return map([pair]);
+ return map([pair], _scanner.spanFrom(start));
}
// 151
- _Pair<Node, Node> ns_flowPairEntry(int indent, int ctx) => or([
+ Pair<Node, Node> ns_flowPairEntry(int indent, int ctx) => or([
() => ns_flowPairYamlKeyEntry(indent, ctx),
() => c_ns_flowMapEmptyKeyEntry(indent, ctx),
() => c_ns_flowPairJsonKeyEntry(indent, ctx)
]);
// 152
- _Pair<Node, Node> ns_flowPairYamlKeyEntry(int indent, int ctx) =>
+ Pair<Node, Node> ns_flowPairYamlKeyEntry(int indent, int ctx) =>
transaction(() {
var key = ns_s_implicitYamlKey(FLOW_KEY);
if (!truth(key)) return null;
var value = c_ns_flowMapSeparateValue(indent, ctx);
if (!truth(value)) return null;
- return new _Pair<Node, Node>(key, value);
+ return new Pair<Node, Node>(key, value);
});
// 153
- _Pair<Node, Node> c_ns_flowPairJsonKeyEntry(int indent, int ctx) =>
+ Pair<Node, Node> c_ns_flowPairJsonKeyEntry(int indent, int ctx) =>
transaction(() {
var key = c_s_implicitJsonKey(FLOW_KEY);
if (!truth(key)) return null;
var value = c_ns_flowMapAdjacentValue(indent, ctx);
if (!truth(value)) return null;
- return new _Pair<Node, Node>(key, value);
+ return new Pair<Node, Node>(key, value);
});
// 154
@@ -1288,9 +1297,10 @@
// 156
Node ns_flowYamlContent(int indent, int ctx) {
+ var start = _scanner.state;
var str = ns_plain(indent, ctx);
if (!truth(str)) return null;
- return new ScalarNode("?", content: str);
+ return new ScalarNode("?", _scanner.spanFrom(start), content: str);
}
// 157
@@ -1437,6 +1447,7 @@
// 170
Node c_l_literal(int indent) => transaction(() {
+ var start = _scanner.state;
if (!truth(c_indicator(C_LITERAL))) return null;
var header = c_b_blockHeader();
if (!truth(header)) return null;
@@ -1445,7 +1456,7 @@
var content = l_literalContent(indent + additionalIndent, header.chomping);
if (!truth(content)) return null;
- return new ScalarNode("!", content: content);
+ return new ScalarNode("!", _scanner.spanFrom(start), content: content);
});
// 171
@@ -1474,6 +1485,7 @@
// 174
Node c_l_folded(int indent) => transaction(() {
+ var start = _scanner.state;
if (!truth(c_indicator(C_FOLDED))) return null;
var header = c_b_blockHeader();
if (!truth(header)) return null;
@@ -1482,7 +1494,7 @@
var content = l_foldedContent(indent + additionalIndent, header.chomping);
if (!truth(content)) return null;
- return new ScalarNode("!", content: content);
+ return new ScalarNode("!", _scanner.spanFrom(start), content: content);
});
// 175
@@ -1562,13 +1574,14 @@
var additionalIndent = countIndentation() - indent;
if (additionalIndent <= 0) return null;
+ var start = _scanner.state;
var content = oneOrMore(() => transaction(() {
if (!truth(s_indent(indent + additionalIndent))) return null;
return c_l_blockSeqEntry(indent + additionalIndent);
}));
if (!truth(content)) return null;
- return new SequenceNode("?", content);
+ return new SequenceNode("?", content, _scanner.spanFrom(start));
});
// 184
@@ -1595,6 +1608,7 @@
// 186
Node ns_l_compactSequence(int indent) => context('sequence', () {
+ var start = _scanner.state;
var first = c_l_blockSeqEntry(indent);
if (!truth(first)) return null;
@@ -1604,7 +1618,7 @@
}));
content.insert(0, first);
- return new SequenceNode("?", content);
+ return new SequenceNode("?", content, _scanner.spanFrom(start));
});
// 187
@@ -1612,23 +1626,24 @@
var additionalIndent = countIndentation() - indent;
if (additionalIndent <= 0) return null;
+ var start = _scanner.state;
var pairs = oneOrMore(() => transaction(() {
if (!truth(s_indent(indent + additionalIndent))) return null;
return ns_l_blockMapEntry(indent + additionalIndent);
}));
if (!truth(pairs)) return null;
- return map(pairs);
+ return map(pairs, _scanner.spanFrom(start));
});
// 188
- _Pair<Node, Node> ns_l_blockMapEntry(int indent) => or([
+ Pair<Node, Node> ns_l_blockMapEntry(int indent) => or([
() => c_l_blockMapExplicitEntry(indent),
() => ns_l_blockMapImplicitEntry(indent)
]);
// 189
- _Pair<Node, Node> c_l_blockMapExplicitEntry(int indent) {
+ Pair<Node, Node> c_l_blockMapExplicitEntry(int indent) {
var key = c_l_blockMapExplicitKey(indent);
if (!truth(key)) return null;
@@ -1637,7 +1652,7 @@
e_node
]);
- return new _Pair<Node, Node>(key, value);
+ return new Pair<Node, Node>(key, value);
}
// 190
@@ -1654,10 +1669,10 @@
});
// 192
- _Pair<Node, Node> ns_l_blockMapImplicitEntry(int indent) => transaction(() {
+ Pair<Node, Node> ns_l_blockMapImplicitEntry(int indent) => transaction(() {
var key = or([ns_s_blockMapImplicitKey, e_node]);
var value = c_l_blockMapImplicitValue(indent);
- return truth(value) ? new _Pair<Node, Node>(key, value) : null;
+ return truth(value) ? new Pair<Node, Node>(key, value) : null;
});
// 193
@@ -1678,6 +1693,7 @@
// 195
Node ns_l_compactMapping(int indent) => context('mapping', () {
+ var start = _scanner.state;
var first = ns_l_blockMapEntry(indent);
if (!truth(first)) return null;
@@ -1687,7 +1703,7 @@
}));
pairs.insert(0, first);
- return map(pairs);
+ return map(pairs, _scanner.spanFrom(start));
});
// 196
@@ -1807,7 +1823,8 @@
or([l_directiveDocument, l_explicitDocument, l_bareDocument]);
// 211
- List<Node> l_yamlStream() {
+ Pair<List<Node>, Span> l_yamlStream() {
+ var start = _scanner.state;
var docs = [];
zeroOrMore(l_documentPrefix);
var first = zeroOrOne(l_anyDocument);
@@ -1828,20 +1845,10 @@
});
if (!_scanner.isDone) parseFailed();
- return docs;
+ return new Pair(docs, _scanner.spanFrom(start));
}
}
-/// A pair of values.
-class _Pair<E, F> {
- E first;
- F last;
-
- _Pair(this.first, this.last);
-
- String toString() => '($first, $last)';
-}
-
/// The information in the header for a block scalar.
class _BlockHeader {
final int additionalIndent;
@@ -1872,7 +1879,7 @@
/// expensive.
class _RangeMap<E> {
/// The ranges and their associated elements.
- final List<_Pair<_Range, E>> _contents = <_Pair<_Range, E>>[];
+ final List<Pair<_Range, E>> _contents = <Pair<_Range, E>>[];
_RangeMap();
@@ -1890,5 +1897,5 @@
/// Associates [value] with [range].
operator[]=(_Range range, E value) =>
- _contents.add(new _Pair<_Range, E>(range, value));
+ _contents.add(new Pair<_Range, E>(range, value));
}
diff --git a/pkgs/yaml/lib/src/utils.dart b/pkgs/yaml/lib/src/utils.dart
index 463af70..84c1113 100644
--- a/pkgs/yaml/lib/src/utils.dart
+++ b/pkgs/yaml/lib/src/utils.dart
@@ -4,33 +4,12 @@
library yaml.utils;
-import 'package:collection/collection.dart';
+/// A pair of values.
+class Pair<E, F> {
+ final E first;
+ final F last;
-/// Returns a hash code for [obj] such that structurally equivalent objects
-/// will have the same hash code.
-///
-/// This supports deep equality for maps and lists, including those with
-/// self-referential structures.
-int hashCodeFor(obj) {
- var parents = [];
+ Pair(this.first, this.last);
- _hashCodeFor(value) {
- if (parents.any((parent) => identical(parent, value))) return -1;
-
- parents.add(value);
- try {
- if (value is Map) {
- var equality = const UnorderedIterableEquality();
- return equality.hash(value.keys.map(_hashCodeFor)) ^
- equality.hash(value.values.map(_hashCodeFor));
- } else if (value is Iterable) {
- return const IterableEquality().hash(value.map(hashCodeFor));
- }
- return value.hashCode;
- } finally {
- parents.removeLast();
- }
- }
-
- return _hashCodeFor(obj);
+ String toString() => '($first, $last)';
}
diff --git a/pkgs/yaml/lib/src/visitor.dart b/pkgs/yaml/lib/src/visitor.dart
index 7095268..3f4c455 100644
--- a/pkgs/yaml/lib/src/visitor.dart
+++ b/pkgs/yaml/lib/src/visitor.dart
@@ -4,8 +4,8 @@
library yaml.visitor;
+import 'equality.dart';
import 'model.dart';
-import 'yaml_map.dart';
/// The visitor pattern for YAML documents.
class Visitor {
@@ -21,7 +21,7 @@
/// Visits each key and value in [map] and returns a map of the results.
visitMapping(MappingNode map) {
- var out = new YamlMap();
+ var out = deepEqualsMap();
for (var key in map.content.keys) {
out[key.visit(this)] = map.content[key].visit(this);
}
diff --git a/pkgs/yaml/lib/src/yaml_map.dart b/pkgs/yaml/lib/src/yaml_map.dart
deleted file mode 100644
index ff3da36..0000000
--- a/pkgs/yaml/lib/src/yaml_map.dart
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library yaml.map;
-
-import 'dart:collection';
-
-import 'package:collection/collection.dart';
-
-import 'deep_equals.dart';
-import 'utils.dart';
-
-/// This class behaves almost identically to the normal Dart [Map]
-/// implementation, with the following differences:
-///
-/// * It allows NaN, list, and map keys.
-/// * It defines `==` structurally. That is, `yamlMap1 == yamlMap2` if they
-/// have the same contents.
-/// * It has a compatible [hashCode] method.
-///
-/// This class is deprecated. In future releases, this package will use
-/// a [HashMap] with a custom equality operation rather than a custom class.
-@Deprecated('1.0.0')
-class YamlMap extends DelegatingMap {
- YamlMap()
- : super(new HashMap(equals: deepEquals, hashCode: hashCodeFor));
-
- YamlMap.from(Map map)
- : super(new HashMap(equals: deepEquals, hashCode: hashCodeFor)) {
- addAll(map);
- }
-
- int get hashCode => hashCodeFor(this);
-
- bool operator ==(other) {
- if (other is! YamlMap) return false;
- return deepEquals(this, other);
- }
-}
diff --git a/pkgs/yaml/lib/src/yaml_node.dart b/pkgs/yaml/lib/src/yaml_node.dart
new file mode 100644
index 0000000..d0e0578
--- /dev/null
+++ b/pkgs/yaml/lib/src/yaml_node.dart
@@ -0,0 +1,92 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library yaml.map;
+
+import 'dart:collection' as collection;
+
+import 'package:collection/collection.dart';
+import 'package:source_maps/source_maps.dart';
+
+/// An interface for parsed nodes from a YAML source tree.
+///
+/// [YamlMap]s and [YamlList]s implement this interface in addition to the
+/// normal [Map] and [List] interfaces, so any maps and lists will be
+/// [YamlNode]s regardless of how they're accessed.
+///
+/// Scalars values like strings and numbers, on the other hand, don't have this
+/// interface by default. Instead, they can be accessed as [YamlScalar]s via
+/// [YamlMap.nodes] or [YamlList.nodes].
+abstract class YamlNode {
+ /// The source span for this node.
+ ///
+ /// [Span.getLocationMessage] can be used to produce a human-friendly message
+ /// about this node.
+ Span get span;
+
+ /// The inner value of this node.
+ ///
+ /// For [YamlScalar]s, this will return the wrapped value. For [YamlMap] and
+ /// [YamlList], it will return [this], since they already implement [Map] and
+ /// [List], respectively.
+ get value;
+}
+
+/// A read-only [Map] parsed from YAML.
+class YamlMap extends YamlNode with collection.MapMixin, UnmodifiableMapMixin {
+ final Span span;
+
+ final Map<dynamic, YamlNode> nodes;
+
+ Map get value => this;
+
+ Iterable get keys => nodes.keys.map((node) => node.value);
+
+ /// Users of the library should not construct [YamlMap]s manually.
+ YamlMap(Map<dynamic, YamlNode> nodes, this.span)
+ : nodes = new UnmodifiableMapView<dynamic, YamlNode>(nodes);
+
+ operator [](key) {
+ var node = nodes[key];
+ return node == null ? null : node.value;
+ }
+}
+
+// TODO(nweiz): Use UnmodifiableListMixin when issue 18970 is fixed.
+/// A read-only [List] parsed from YAML.
+class YamlList extends YamlNode with collection.ListMixin {
+ final Span span;
+
+ final List<YamlNode> nodes;
+
+ List get value => this;
+
+ int get length => nodes.length;
+
+ set length(int index) {
+ throw new UnsupportedError("Cannot modify an unmodifiable List");
+ }
+
+ /// Users of the library should not construct [YamlList]s manually.
+ YamlList(List<YamlNode> nodes, this.span)
+ : nodes = new UnmodifiableListView<YamlNode>(nodes);
+
+ operator [](int index) => nodes[index].value;
+
+ operator []=(int index, value) {
+ throw new UnsupportedError("Cannot modify an unmodifiable List");
+ }
+}
+
+/// A wrapped scalar value parsed from YAML.
+class YamlScalar extends YamlNode {
+ final Span span;
+
+ final value;
+
+ /// Users of the library should not construct [YamlScalar]s manually.
+ YamlScalar(this.value, this.span);
+
+ String toString() => value.toString();
+}
diff --git a/pkgs/yaml/lib/yaml.dart b/pkgs/yaml/lib/yaml.dart
index 209db8c..f59719d 100644
--- a/pkgs/yaml/lib/yaml.dart
+++ b/pkgs/yaml/lib/yaml.dart
@@ -8,9 +8,10 @@
import 'src/constructor.dart';
import 'src/parser.dart';
import 'src/yaml_exception.dart';
+import 'src/yaml_node.dart';
export 'src/yaml_exception.dart';
-export 'src/yaml_map.dart';
+export 'src/yaml_node.dart';
/// Loads a single document from a YAML string.
///
@@ -28,12 +29,20 @@
///
/// If [sourceName] is passed, it's used as the name of the file or URL from
/// which the YAML originated for error reporting.
-loadYaml(String yaml, {String sourceName}) {
+loadYaml(String yaml, {String sourceName}) =>
+ loadYamlNode(yaml, sourceName: sourceName).value;
+
+/// Loads a single document from a YAML string as a [YamlNode].
+///
+/// This is just like [loadYaml], except that where [loadYaml] would return a
+/// normal Dart value this returns a [YamlNode] instead. This allows the caller
+/// to be confident that the return value will always be a [YamlNode].
+YamlNode loadYamlNode(String yaml, {String sourceName}) {
var stream = loadYamlStream(yaml, sourceName: sourceName);
if (stream.length != 1) {
throw new YamlException("Expected 1 document, were ${stream.length}.");
}
- return stream[0];
+ return stream.nodes[0];
}
/// Loads a stream of documents from a YAML string.
@@ -49,15 +58,16 @@
///
/// If [sourceName] is passed, it's used as the name of the file or URL from
/// which the YAML originated for error reporting.
-List loadYamlStream(String yaml, {String sourceName}) {
- var stream;
+YamlList loadYamlStream(String yaml, {String sourceName}) {
+ var pair;
try {
- stream = new Parser(yaml, sourceName).l_yamlStream();
+ pair = new Parser(yaml, sourceName).l_yamlStream();
} on FormatException catch (error) {
throw new YamlException(error.toString());
}
- return stream
+ var nodes = pair.first
.map((doc) => new Constructor(new Composer(doc).compose()).construct())
.toList();
+ return new YamlList(nodes, pair.last);
}
diff --git a/pkgs/yaml/pubspec.yaml b/pkgs/yaml/pubspec.yaml
index b57224c..2672161 100644
--- a/pkgs/yaml/pubspec.yaml
+++ b/pkgs/yaml/pubspec.yaml
@@ -1,5 +1,5 @@
name: yaml
-version: 0.10.0
+version: 1.0.0
author: "Dart Team <misc@dartlang.org>"
homepage: http://www.dartlang.org
description: A parser for YAML.
diff --git a/pkgs/yaml/test/utils.dart b/pkgs/yaml/test/utils.dart
index 0bac9f9..9c96ec1 100644
--- a/pkgs/yaml/test/utils.dart
+++ b/pkgs/yaml/test/utils.dart
@@ -5,7 +5,7 @@
library yaml.test.utils;
import 'package:unittest/unittest.dart';
-import 'package:yaml/src/deep_equals.dart' as de;
+import 'package:yaml/src/equality.dart' as equality;
import 'package:yaml/yaml.dart';
/// A matcher that validates that a closure or Future throws a [YamlException].
@@ -14,25 +14,28 @@
/// Returns a matcher that asserts that the value equals [expected].
///
/// This handles recursive loops and considers `NaN` to equal itself.
-Matcher deepEquals(expected) =>
- predicate((actual) => de.deepEquals(actual, expected), "equals $expected");
+Matcher deepEquals(expected) => predicate((actual) =>
+ equality.deepEquals(actual, expected), "equals $expected");
/// Constructs a new yaml.YamlMap, optionally from a normal Map.
-Map yamlMap([Map from]) =>
- from == null ? new YamlMap() : new YamlMap.from(from);
+Map deepEqualsMap([Map from]) {
+ var map = equality.deepEqualsMap();
+ if (from != null) map.addAll(from);
+ return map;
+}
/// Asserts that a string containing a single YAML document produces a given
/// value when loaded.
void expectYamlLoads(expected, String source) {
var actual = loadYaml(cleanUpLiteral(source));
- expect(expected, deepEquals(actual));
+ expect(actual, deepEquals(expected));
}
/// Asserts that a string containing a stream of YAML documents produces a given
/// list of values when loaded.
void expectYamlStreamLoads(List expected, String source) {
var actual = loadYamlStream(cleanUpLiteral(source));
- expect(expected, deepEquals(actual));
+ expect(actual, deepEquals(expected));
}
/// Asserts that a string containing a single YAML document throws a
diff --git a/pkgs/yaml/test/yaml_test.dart b/pkgs/yaml/test/yaml_test.dart
index fcfc12e..4fbb108 100644
--- a/pkgs/yaml/test/yaml_test.dart
+++ b/pkgs/yaml/test/yaml_test.dart
@@ -14,37 +14,6 @@
var infinity = double.parse("Infinity");
var nan = double.parse("NaN");
- group('YamlMap', () {
- group('accepts as a key', () {
- _expectKeyWorks(keyFn()) {
- var map = yamlMap();
- map[keyFn()] = 5;
- expect(map.containsKey(keyFn()), isTrue);
- expect(map[keyFn()], 5);
- }
-
- test('null', () => _expectKeyWorks(() => null));
- test('true', () => _expectKeyWorks(() => true));
- test('false', () => _expectKeyWorks(() => false));
- test('a list', () => _expectKeyWorks(() => [1, 2, 3]));
- test('a map', () => _expectKeyWorks(() => {'foo': 'bar'}));
- test('a YAML map', () => _expectKeyWorks(() => yamlMap({'foo': 'bar'})));
- });
-
- test('works as a hash key', () {
- var normalMap = new Map();
- normalMap[yamlMap({'foo': 'bar'})] = 'baz';
- expect(normalMap.containsKey(yamlMap({'foo': 'bar'})), isTrue);
- expect(normalMap[yamlMap({'foo': 'bar'})], 'baz');
- });
-
- test('treats YamlMap keys the same as normal maps', () {
- var map = yamlMap();
- map[{'a': 'b'}] = 5;
- expect(map[yamlMap({'a': 'b'})], 5);
- });
- });
-
group('has a friendly error message for', () {
var tabError = predicate((e) =>
e.toString().contains('tab characters are not allowed as indentation'));
@@ -221,7 +190,7 @@
// });
test('[Example 2.11]', () {
- var doc = yamlMap();
+ var doc = deepEqualsMap();
doc[["Detroit Tigers", "Chicago cubs"]] = ["2001-07-23"];
doc[["New York Yankees", "Atlanta Braves"]] =
["2001-07-02", "2001-08-12", "2001-08-14"];
@@ -382,7 +351,7 @@
});
test('[Example 2.21]', () {
- var doc = yamlMap({
+ var doc = deepEqualsMap({
"booleans": [true, false],
"string": "012345"
});
@@ -900,7 +869,7 @@
});
test('[Example 6.12]', () {
- var doc = yamlMap();
+ var doc = deepEqualsMap();
doc[{'first': 'Sammy', 'last': 'Sosa'}] = {
'hr': 65,
'avg': 0.278
@@ -1092,7 +1061,7 @@
// });
test('[Example 7.3]', () {
- var doc = yamlMap({"foo": null});
+ var doc = deepEqualsMap({"foo": null});
doc[null] = "bar";
expectYamlLoads(doc,
"""
@@ -1239,7 +1208,7 @@
});
test('[Example 7.16]', () {
- var doc = yamlMap({
+ var doc = deepEqualsMap({
"explicit": "entry",
"implicit": "entry"
});
@@ -1254,7 +1223,7 @@
});
test('[Example 7.17]', () {
- var doc = yamlMap({
+ var doc = deepEqualsMap({
"unquoted": "separate",
"http://foo.com": null,
"omitted value": null
@@ -1302,10 +1271,10 @@
});
test('[Example 7.21]', () {
- var el1 = yamlMap();
+ var el1 = deepEqualsMap();
el1[null] = "empty key entry";
- var el2 = yamlMap();
+ var el2 = deepEqualsMap();
el2[{"JSON": "like"}] = "adjacent";
expectYamlLoads([[{"YAML": "separate"}], [el1], [el2]],
@@ -1577,7 +1546,7 @@
});
test('[Example 8.18]', () {
- var doc = yamlMap({
+ var doc = deepEqualsMap({
'plain key': 'in-line value',
"quoted key": ["entry"]
});
@@ -1591,7 +1560,7 @@
});
test('[Example 8.19]', () {
- var el = yamlMap();
+ var el = deepEqualsMap();
el[{'earth': 'blue'}] = {'moon': 'white'};
expectYamlLoads([{'sun': 'yellow'}, el],
"""
@@ -1763,7 +1732,7 @@
group('10.2: JSON Schema', () {
// test('[Example 10.4]', () {
- // var doc = yamlMap({"key with null value": null});
+ // var doc = deepEqualsMap({"key with null value": null});
// doc[null] = "value for null key";
// expectYamlStreamLoads(doc,
// """