Skip to content

Commit f6abf31

Browse files
committed
Parse tag handles correctly
* Avoid eagerly buffering the tag uri when we can scan the uri and check later. * Throw if a local tag prefix has a secondary/named handle.
1 parent 7870e49 commit f6abf31

File tree

1 file changed

+44
-15
lines changed

1 file changed

+44
-15
lines changed

pkgs/yaml/lib/src/scanner.dart

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,26 +1018,55 @@ class Scanner {
10181018
}
10191019

10201020
/// Scans a tag handle.
1021-
String _scanTagHandle({bool directive = false}) {
1021+
///
1022+
/// If [isPrefix] is `true`, the handle can never be a secondary or named
1023+
/// tag handle. Such handles cannot be used in a global tag's local tag
1024+
/// prefix.
1025+
///
1026+
/// See: https://yaml.org/spec/1.2/spec.html#id2783273
1027+
String _scanTagHandle({bool directive = false, bool isPrefix = false}) {
1028+
final start = _scanner.state;
10221029
_scanner.expect('!');
10231030

1024-
var buffer = StringBuffer('!');
1025-
1026-
// libyaml only allows word characters in tags, but the spec disagrees:
1027-
// http://yaml.org/spec/1.2/spec.html#ns-tag-char.
1028-
var start = _scanner.position;
1029-
while (_isTagChar) {
1030-
_scanner.readChar();
1031-
}
1032-
buffer.write(_scanner.substring(start));
1031+
final buffer = StringBuffer('!');
10331032

10341033
if (_scanner.peekChar() == EXCLAMATION) {
1035-
buffer.writeCharCode(_scanner.readCodePoint());
1034+
// TODO: Do we really need this highlighted?
1035+
final char = _scanner.readCodePoint();
1036+
1037+
if (isPrefix) {
1038+
throw YamlException(
1039+
'A local tag used as a global tag prefix cannot have a secondary tag'
1040+
' handle',
1041+
_scanner.spanFrom(start),
1042+
);
1043+
}
1044+
1045+
buffer.writeCharCode(char);
10361046
} else {
1037-
// It's either the '!' tag or not really a tag handle. If it's a %TAG
1038-
// directive, it's an error. If it's a tag token, it must be part of a
1039-
// URI.
1040-
if (directive && buffer.toString() != '!') _scanner.expect('!');
1047+
// Both %TAG and tag shorthands can have named handles.
1048+
buffer.write(_scanTagUri(flowSeparators: false));
1049+
1050+
/// For directives, expect the "!" for a named tag. No other handle can
1051+
/// have a tag uri here. For a tag shorthand anywhere else, this needs to
1052+
/// be a separation space (tab included) or line break or nothing.
1053+
if (buffer.length > 1 && !_isBlankOrEnd) {
1054+
_scanner.expect('!');
1055+
1056+
/// A tag directive doesn't allow a local tag with a named handle as a
1057+
/// local tag prefix.
1058+
///
1059+
/// See: https://yaml.org/spec/1.2/spec.html#id2783273
1060+
if (directive && isPrefix) {
1061+
throw YamlException(
1062+
'A local tag used as a global tag prefix cannot have a named tag'
1063+
' handle',
1064+
_scanner.spanFrom(start),
1065+
);
1066+
}
1067+
1068+
buffer.write('!');
1069+
}
10411070
}
10421071

10431072
return buffer.toString();

0 commit comments

Comments
 (0)