Merge branch 'master' into null_safety-migration
diff --git a/analysis_options.yaml b/analysis_options.yaml
index e608f4c..87e8300 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -17,7 +17,7 @@
     - await_only_futures
     - camel_case_types
     - cancel_subscriptions
-    #- comment_references
+    - comment_references
     # See https://github.com/dart-lang/logging/issues/43
     #- constant_identifier_names
     - control_flow_in_finally
diff --git a/lib/dom.dart b/lib/dom.dart
index 403de3f..2f2496d 100644
--- a/lib/dom.dart
+++ b/lib/dom.dart
@@ -84,7 +84,7 @@
   /// [selectors level 4](http://dev.w3.org/csswg/selectors-4/)
   /// are implemented. For example, nth-child does not implement An+B syntax
   /// and *-of-type is not implemented. If a selector is not implemented this
-  /// method will throw [UniplmentedError].
+  /// method will throw [UnimplementedError].
   Element? querySelector(String selector) =>
       query.querySelector(this, selector);
 
@@ -95,7 +95,7 @@
   /// [selectors level 4](http://dev.w3.org/csswg/selectors-4/)
   /// are implemented. For example, nth-child does not implement An+B syntax
   /// and *-of-type is not implemented. If a selector is not implemented this
-  /// method will throw [UniplmentedError].
+  /// method will throw [UnimplementedError].
   List<Element> querySelectorAll(String selector) =>
       query.querySelectorAll(this, selector);
 }
@@ -182,7 +182,7 @@
   }
 
   /// If [sourceSpan] is available, this contains the spans of each attribute's
-  /// value. Unlike [attributeSpans], this span will inlcude only the value.
+  /// value. Unlike [attributeSpans], this span will include only the value.
   /// For example, the value span of "attr" in `<a attr="value">` would be the
   /// text `value`.
   LinkedHashMap<Object, FileSpan>? get attributeValueSpans {
@@ -236,9 +236,6 @@
   }
 
   /// Insert [node] as a child of the current node, before [refNode] in the
-  /// list of child nodes. Raises [UnsupportedOperationException] if [refNode]
-  /// is not a child of the current node. If refNode is null, this adds to the
-  /// end of the list.
   void insertBefore(Node node, Node? refNode) {
     if (refNode == null) {
       nodes.add(node);
@@ -504,7 +501,7 @@
     //    creating them every call.
     // 2) Verify that the html does not contain leading or trailing text nodes.
     // 3) Verify that the html does not contain both <head> and <body> tags.
-    // 4) Detatch the created element from its dummy parent.
+    // 4) Detach the created element from its dummy parent.
     var parentTag = 'div';
     String? tag;
     final match = _startTagRegexp.firstMatch(html);
diff --git a/lib/parser.dart b/lib/parser.dart
index c085e08..ca193f0 100644
--- a/lib/parser.dart
+++ b/lib/parser.dart
@@ -139,7 +139,7 @@
   /// Set [lowercaseElementName] or [lowercaseAttrName] to false to disable the
   /// automatic conversion of element and attribute names to lower case. Note
   /// that standard way to parse HTML is to lowercase, which is what the browser
-  /// DOM will do if you request [Node.outerHTML], for example.
+  /// DOM will do if you request `Element.outerHTML`, for example.
   HtmlParser(input,
       {String? encoding,
       bool parseMeta = true,
@@ -3951,12 +3951,10 @@
 
   int get column => span!.start.column;
 
-  /// Gets the human readable error message for this error. Use
-  /// [span.getLocationMessage] or [toString] to get a message including span
-  /// information. If there is a file associated with the span, both
-  /// [span.getLocationMessage] and [toString] are equivalent. Otherwise,
-  /// [span.getLocationMessage] will not show any source url information, but
-  /// [toString] will include 'ParserError:' as a prefix.
+  /// Returns the human readable error message for this error.
+  ///
+  /// Use [SourceSpan.message] or the [toString] from the [span] field to get a
+  /// message including span information
   @override
   String get message => formatStr(errorMessages[errorCode]!, data);
 
diff --git a/lib/src/constants.dart b/lib/src/constants.dart
index 52c08d7..2c013d4 100644
--- a/lib/src/constants.dart
+++ b/lib/src/constants.dart
@@ -15,9 +15,11 @@
 
 // TODO(jmesserly): assuming the programmatic name is not important, it would be
 // good to make these "static const" fields on an ErrorMessage class.
-/// These are error messages emitted by [HtmlParser]. The values use Python
-/// style string formatting, as implemented by [formatStr]. That function only
-/// supports the subset of format functionality used here.
+/// Error messages emitted by `HtmlParser`.
+///
+/// The values use Python style string formatting, as implemented by
+/// [formatStr]. That function only supports the subset of format functionality
+/// used here.
 const Map<String, String> errorMessages = {
   'null-character': 'Null character in input stream, replaced with U+FFFD.',
   'invalid-codepoint': 'Invalid codepoint in stream.',
diff --git a/lib/src/html_input_stream.dart b/lib/src/html_input_stream.dart
index 2f021a0..60bf8f8 100644
--- a/lib/src/html_input_stream.dart
+++ b/lib/src/html_input_stream.dart
@@ -43,13 +43,13 @@
 
   var _offset = 0;
 
-  /// Initialises the HtmlInputStream.
+  /// Initialise an HtmlInputStream.
   ///
   /// HtmlInputStream(source, [encoding]) -> Normalized stream from source
   /// for use by html5lib.
   ///
   /// [source] can be either a [String] or a [List<int>] containing the raw
-  /// bytes, or a file if [consoleSupport] is initialized.
+  /// bytes.
   ///
   /// The optional encoding parameter must be a string that indicates
   /// the encoding.  If specified, that encoding will be used,
diff --git a/lib/src/token.dart b/lib/src/token.dart
index 8d995bc..b2c3f40 100644
--- a/lib/src/token.dart
+++ b/lib/src/token.dart
@@ -21,7 +21,7 @@
 
 class StartTagToken extends TagToken {
   /// The tag's attributes. A map from the name to the value, where the name
-  /// can be a [String] or [AttributeName].
+  /// can be a [String] or `AttributeName`.
   LinkedHashMap<Object, String> data;
 
   /// The attribute spans if requested. Otherwise null.
diff --git a/test/parser_test.dart b/test/parser_test.dart
index 1e35916..06fb4c6 100644
--- a/test/parser_test.dart
+++ b/test/parser_test.dart
@@ -69,8 +69,8 @@
   }
 }
 
-void main() {
-  for (var path in getDataFiles('tree-construction')) {
+void main() async {
+  await for (var path in dataFiles('tree-construction')) {
     if (!path.endsWith('.dat')) continue;
 
     final tests = TestData(path, 'data');
diff --git a/test/selectors/level1_baseline_test.dart b/test/selectors/level1_baseline_test.dart
index a97f130..cba4c21 100644
--- a/test/selectors/level1_baseline_test.dart
+++ b/test/selectors/level1_baseline_test.dart
@@ -17,15 +17,16 @@
 import 'level1_lib.dart';
 import 'selectors.dart';
 
-Document getTestContentDocument() {
-  final testPath = p.join(testDir, 'selectors', 'level1-content.html');
+Future<Document> testContentDocument() async {
+  final testPath =
+      p.join(await testDirectory, 'selectors', 'level1-content.html');
   return parse(File(testPath).readAsStringSync());
 }
 
 var testType = testQsaBaseline; // Only run baseline tests.
 var docType = 'html'; // Only run tests suitable for HTML
 
-void main() {
+void main() async {
   /*
    * This test suite tests Selectors API methods in 4 different contexts:
    * 1. Document node
@@ -62,7 +63,7 @@
 
   // Prepare the nodes for testing
   //doc = frame.contentDocument;                 // Document Node tests
-  doc = getTestContentDocument();
+  doc = await testContentDocument();
 
   final element = doc.getElementById('root')!; // In-document Element Node tests
 
diff --git a/test/support.dart b/test/support.dart
index 34fb8a0..83894af 100644
--- a/test/support.dart
+++ b/test/support.dart
@@ -3,6 +3,7 @@
 
 import 'dart:collection';
 import 'dart:io';
+import 'dart:isolate';
 
 import 'package:path/path.dart' as p;
 import 'package:html/src/treebuilder.dart';
@@ -18,13 +19,20 @@
   return _treeTypes;
 }
 
-final testDir = p.join(p.dirname(p.fromUri(Platform.packageConfig)), 'test');
+Future<String> get testDirectory async {
+  final packageUriDir = p.dirname(p.fromUri(await Isolate.resolvePackageUri(
+      Uri(scheme: 'package', path: 'html/html.dart'))));
+  // Assume pub layout - root is parent directory to package URI (`lib/`).
+  final rootPackageDir = p.dirname(packageUriDir);
+  return p.join(rootPackageDir, 'test');
+}
 
-final testDataDir = p.join(testDir, 'data');
-
-Iterable<String> getDataFiles(String subdirectory) {
-  final dir = Directory(p.join(testDataDir, subdirectory));
-  return dir.listSync().whereType<File>().map((f) => f.path);
+Stream<String> dataFiles(String subdirectory) async* {
+  final dir = Directory(p.join(await testDirectory, 'data', subdirectory));
+  await for (final file in dir.list()) {
+    if (file is! File) continue;
+    yield file.path;
+  }
 }
 
 // TODO(jmesserly): make this class simpler. We could probably split on
diff --git a/test/tokenizer_test.dart b/test/tokenizer_test.dart
index e0700a2..87ba6d0 100644
--- a/test/tokenizer_test.dart
+++ b/test/tokenizer_test.dart
@@ -258,8 +258,8 @@
   return result.toString();
 }
 
-void main() {
-  for (var path in getDataFiles('tokenizer')) {
+void main() async {
+  await for (var path in dataFiles('tokenizer')) {
     if (!path.endsWith('.test')) continue;
 
     final text = File(path).readAsStringSync();