[html] Fix unquoted content charset parsing and deduplicate _insertText
diff --git a/pkgs/html/CHANGELOG.md b/pkgs/html/CHANGELOG.md
index baf0d1f..fd7c63a 100644
--- a/pkgs/html/CHANGELOG.md
+++ b/pkgs/html/CHANGELOG.md
@@ -3,10 +3,10 @@
 - Fix `Node.attributeSpans` and `Node.attributeValueSpans` throwing a `TypeError` when a start tag emits tokenizer parse errors, and preserve the first occurrence's span on duplicate attributes.
 - Fix `HtmlInputStream` throwing a `FormatException` on malformed UTF-8 or invalid ASCII byte sequences, and ignore `<meta charset>` declarations that resolve to unsupported Dart codecs.
 - Fix `HtmlTokenizer.consumeNumberEntity` throwing a `FormatException` when a numeric character reference overflows a 64-bit integer.
-- Fix `EncodingParser` failing to parse `<meta charset>` attributes with whitespace before `=` and `EncodingBytes` throwing a `RangeError` at offset 0.
+- Fix `EncodingParser` failing to parse `<meta charset>` attributes with whitespace before `=`, unquoted `charset` values at the end of `content` attributes, and `EncodingBytes` throwing a `RangeError` at offset 0.
 - Fix `querySelector` and `querySelectorAll` throwing a null-check `TypeError` instead of `FormatException` on empty `:not()` selectors.
 - Fix `TreeBuilder` not updating `Text.sourceSpan` when merging consecutive foster-parented text nodes before a `<table>`.
-- Fix `ParseError.message` throwing a null-check `TypeError` on `self-closing-flag-on-end-tag`, `expected-end-of-tag-name-but-got-eof`, and `unexpected-EOF-after-attribute-value` tokenizer errors.
+- Fix `ParseError.message` throwing a null-check `TypeError` on `unexpected-EOF-after-attribute-value` tokenizer errors.
 
 ## 0.15.7
 
diff --git a/pkgs/html/lib/parser.dart b/pkgs/html/lib/parser.dart
index 5a6fd50..7425965 100644
--- a/pkgs/html/lib/parser.dart
+++ b/pkgs/html/lib/parser.dart
@@ -3974,8 +3974,7 @@
   /// Use [SourceSpan.message] or the [toString] from the [span] field to get a
   /// message including span information
   @override
-  String get message => formatStr(
-      errorMessages[errorCode] ?? errorMessages['undefined-error']!, data);
+  String get message => formatStr(errorMessages[errorCode]!, data);
 
   @override
   String toString({dynamic color}) {
diff --git a/pkgs/html/lib/src/encoding_parser.dart b/pkgs/html/lib/src/encoding_parser.dart
index d92fe27..ac220d3 100644
--- a/pkgs/html/lib/src/encoding_parser.dart
+++ b/pkgs/html/lib/src/encoding_parser.dart
@@ -354,7 +354,9 @@
       } else {
         // Unquoted value
         final oldPosition = data._position;
-        data._skipUntil(isWhitespace);
+        if (data._skipUntil(isWhitespace) == null) {
+          return data._slice(oldPosition);
+        }
         return data._slice(oldPosition, data._position);
       }
     } on _EncodingRangeException catch (_) {
diff --git a/pkgs/html/lib/src/treebuilder.dart b/pkgs/html/lib/src/treebuilder.dart
index 521f9d5..0c0ee1c 100644
--- a/pkgs/html/lib/src/treebuilder.dart
+++ b/pkgs/html/lib/src/treebuilder.dart
@@ -278,31 +278,17 @@
   static void _insertText(Node parent, String data, FileSpan? span,
       [Element? refNode]) {
     final nodes = parent.nodes;
-    if (refNode == null) {
-      if (nodes.isNotEmpty && nodes.last is Text) {
-        final last = nodes.last as Text;
-        last.appendData(data);
+    final index = refNode == null ? nodes.length : nodes.indexOf(refNode);
+    if (index > 0 && nodes[index - 1] is Text) {
+      final last = nodes[index - 1] as Text;
+      last.appendData(data);
 
-        if (span != null) {
-          last.sourceSpan =
-              span.file.span(last.sourceSpan!.start.offset, span.end.offset);
-        }
-      } else {
-        nodes.add(Text(data)..sourceSpan = span);
+      if (span != null) {
+        last.sourceSpan =
+            span.file.span(last.sourceSpan!.start.offset, span.end.offset);
       }
     } else {
-      final index = nodes.indexOf(refNode);
-      if (index > 0 && nodes[index - 1] is Text) {
-        final last = nodes[index - 1] as Text;
-        last.appendData(data);
-
-        if (span != null) {
-          last.sourceSpan =
-              span.file.span(last.sourceSpan!.start.offset, span.end.offset);
-        }
-      } else {
-        nodes.insert(index, Text(data)..sourceSpan = span);
-      }
+      nodes.insert(index, Text(data)..sourceSpan = span);
     }
   }
 
diff --git a/pkgs/html/test/parser_feature_test.dart b/pkgs/html/test/parser_feature_test.dart
index dc16b19..f27298e 100644
--- a/pkgs/html/test/parser_feature_test.dart
+++ b/pkgs/html/test/parser_feature_test.dart
@@ -246,6 +246,12 @@
         expect(error.toString(), isNotEmpty);
       }
     }
+    final eofAfterValue = HtmlParser('<div a="1"', generateSpans: true)
+      ..parse();
+    expect(
+      eofAfterValue.errors.map((e) => e.message),
+      contains('Unexpected end of file after attribute value.'),
+    );
   });
 
   test('void element innerHTML', () {
@@ -451,7 +457,15 @@
       expect(
           getEncoding(
               '<meta http-equiv="content-type" content="text/html; charset=UTF-8">'),
-          null);
+          'utf-8');
+      expect(
+          getEncoding(
+              '<meta http-equiv="content-type" content="text/html; charset=UTF-8 ">'),
+          'utf-8');
+      expect(
+          getEncoding(
+              '<meta http-equiv="content-type" content="text/html; charset=\'UTF-8">'),
+          isNull);
     });
   });
 }