Merge pull request #3 from dart-lang/tweaks
A number of fixes for HTML5lib
diff --git a/lib/dom.dart b/lib/dom.dart
index 3c5b332..6201f69 100644
--- a/lib/dom.dart
+++ b/lib/dom.dart
@@ -54,8 +54,8 @@
int compareTo(other) {
// Not sure about this sort order
if (other is! AttributeName) return 1;
- int cmp = (prefix != null ? prefix : "").compareTo(
- (other.prefix != null ? other.prefix : ""));
+ int cmp = (prefix != null ? prefix : "")
+ .compareTo((other.prefix != null ? other.prefix : ""));
if (cmp != 0) return cmp;
cmp = name.compareTo(other.name);
if (cmp != 0) return cmp;
@@ -80,8 +80,7 @@
/// 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].
- Element querySelector(String selector) =>
- query.querySelector(this, selector);
+ Element querySelector(String selector) => query.querySelector(this, selector);
/// Returns all descendant nodes matching the given selectors, using a
/// preorder traversal.
@@ -111,10 +110,9 @@
List<Element> getElementsByTagName(String localName) =>
querySelectorAll(localName);
- List<Element> getElementsByClassName(String classNames) =>
- querySelectorAll(classNames.splitMapJoin(' ',
- onNonMatch: (m) => m.isNotEmpty ? '.$m' : m,
- onMatch: (m) => ''));
+ List<Element> getElementsByClassName(String classNames) => querySelectorAll(
+ classNames.splitMapJoin(' ',
+ onNonMatch: (m) => m.isNotEmpty ? '.$m' : m, onMatch: (m) => ''));
}
/// Really basic implementation of a DOM-core like Node.
@@ -272,46 +270,6 @@
bool contains(Node node) => nodes.contains(node);
- /// Checks if this is a type selector.
- /// See <http://www.w3.org/TR/CSS2/grammar.html>.
- /// Note: this doesn't support '*', the universal selector, non-ascii chars or
- /// escape chars.
- bool _isTypeSelector(String selector) {
- // Parser:
-
- // element_name
- // : IDENT | '*'
- // ;
-
- // Lexer:
-
- // nmstart [_a-z]|{nonascii}|{escape}
- // nmchar [_a-z0-9-]|{nonascii}|{escape}
- // ident -?{nmstart}{nmchar}*
- // nonascii [\240-\377]
- // unicode \\{h}{1,6}(\r\n|[ \t\r\n\f])?
- // escape {unicode}|\\[^\r\n\f0-9a-f]
-
- // As mentioned above, no nonascii or escape support yet.
- int len = selector.length;
- if (len == 0) return false;
-
- int i = 0;
- const int DASH = 45;
- if (selector.codeUnitAt(i) == DASH) i++;
-
- if (i >= len || !isLetter(selector[i])) return false;
- i++;
-
- for (; i < len; i++) {
- if (!isLetterOrDigit(selector[i]) && selector.codeUnitAt(i) != DASH) {
- return false;
- }
- }
-
- return true;
- }
-
/// Initialize [attributeSpans] using [sourceSpan].
void _ensureAttributeSpans() {
if (_attributeSpans != null) return;
@@ -321,8 +279,8 @@
if (sourceSpan == null) return;
- var tokenizer = new HtmlTokenizer(sourceSpan.text, generateSpans: true,
- attributeSpans: true);
+ var tokenizer = new HtmlTokenizer(sourceSpan.text,
+ generateSpans: true, attributeSpans: true);
tokenizer.moveNext();
var token = tokenizer.current as StartTagToken;
@@ -331,8 +289,8 @@
for (var attr in token.attributeSpans) {
var offset = sourceSpan.start.offset;
- _attributeSpans[attr.name] = sourceSpan.file.span(
- offset + attr.start, offset + attr.end);
+ _attributeSpans[attr.name] =
+ sourceSpan.file.span(offset + attr.start, offset + attr.end);
if (attr.startValue != null) {
_attributeValueSpans[attr.name] = sourceSpan.file.span(
offset + attr.startValue, offset + attr.endValue);
@@ -352,7 +310,6 @@
class Document extends Node
with _ParentNode, _NonElementParentNode, _ElementAndDocument {
-
Document() : super._();
factory Document.html(String html) => parse(html);
@@ -389,9 +346,7 @@
DocumentFragment createDocumentFragment() => new DocumentFragment();
}
-class DocumentFragment extends Node
- with _ParentNode, _NonElementParentNode {
-
+class DocumentFragment extends Node with _ParentNode, _NonElementParentNode {
DocumentFragment() : super._();
factory DocumentFragment.html(String html) => parseFragment(html);
@@ -422,7 +377,8 @@
DocumentType(String name, this.publicId, this.systemId)
// Note: once Node.tagName is removed, don't pass "name" to super
- : name = name, super._();
+ : name = name,
+ super._();
int get nodeType => Node.DOCUMENT_TYPE_NODE;
@@ -438,7 +394,6 @@
}
}
-
void _addOuterHtml(StringBuffer str) {
str.write(toString());
}
@@ -460,7 +415,9 @@
Text clone(bool deep) => new Text(data);
String get text => data;
- set text(String value) { data = value; }
+ set text(String value) {
+ data = value;
+ }
}
// TODO(jmesserly): Elements should have a pointer back to their document
@@ -473,7 +430,9 @@
Element._(this.localName, [this.namespaceUri]) : super._();
- Element.tag(this.localName) : namespaceUri = Namespaces.html, super._();
+ Element.tag(this.localName)
+ : namespaceUri = Namespaces.html,
+ super._();
static final _START_TAG_REGEXP = new RegExp('<(\\w+)');
@@ -593,7 +552,8 @@
str.write('>');
if (nodes.length > 0) {
- if (localName == 'pre' || localName == 'textarea' ||
+ if (localName == 'pre' ||
+ localName == 'textarea' ||
localName == 'listing') {
final first = nodes[0];
if (first is Text && first.data.startsWith('\n')) {
@@ -626,7 +586,7 @@
Element clone(bool deep) {
var result = new Element._(localName, namespaceUri)
- ..attributes = new LinkedHashMap.from(attributes);
+ ..attributes = new LinkedHashMap.from(attributes);
return _clone(result, deep);
}
@@ -684,7 +644,6 @@
}
}
-
// TODO(jmesserly): fix this to extend one of the corelib classes if possible.
// (The requirement to remove the node from the old node list makes it tricky.)
// TODO(jmesserly): is there any way to share code with the _NodeListImpl?
@@ -758,7 +717,7 @@
// TODO(jmesserly): These aren't implemented in DOM _NodeListImpl, see
// http://code.google.com/p/dart/issues/detail?id=5371
void setRange(int start, int rangeLength, List<Node> from,
- [int startFrom = 0]) {
+ [int startFrom = 0]) {
if (from is NodeList) {
// Note: this is presumed to make a copy
from = from.sublist(startFrom, startFrom + rangeLength);
@@ -817,14 +776,12 @@
}
}
-
/// An indexable collection of a node's descendants in the document tree,
/// filtered so that only elements are in the collection.
// TODO(jmesserly): this was copied from dart:html
// TODO(jmesserly): "implements List<Element>" is a workaround for analyzer bug.
class FilteredElementList extends IterableBase<Element> with ListMixin<Element>
implements List<Element> {
-
final Node _node;
final List<Node> _childNodes;
@@ -834,7 +791,9 @@
///
/// var filteredElements = new FilteredElementList(query("#container"));
/// // filteredElements is [a, b, c].
- FilteredElementList(Node node): _childNodes = node.nodes, _node = node;
+ FilteredElementList(Node node)
+ : _childNodes = node.nodes,
+ _node = node;
// We can't memoize this, since it's possible that children will be messed
// with externally to this class.
@@ -842,7 +801,7 @@
// TODO(nweiz): we don't always need to create a new list. For example
// forEach, every, any, ... could directly work on the _childNodes.
List<Element> get _filtered =>
- new List<Element>.from(_childNodes.where((n) => n is Element));
+ new List<Element>.from(_childNodes.where((n) => n is Element));
void forEach(void f(Element element)) {
_filtered.forEach(f);
@@ -886,7 +845,7 @@
}
void setRange(int start, int end, Iterable<Element> iterable,
- [int skipCount = 0]) {
+ [int skipCount = 0]) {
throw new UnimplementedError();
}
@@ -957,7 +916,7 @@
bool every(bool f(Element element)) => _filtered.every(f);
bool any(bool f(Element element)) => _filtered.any(f);
- List<Element> toList({ bool growable: true }) =>
+ List<Element> toList({bool growable: true}) =>
new List<Element>.from(this, growable: growable);
Set<Element> toSet() => new Set<Element>.from(this);
Element firstWhere(bool test(Element value), {Element orElse()}) {
@@ -980,12 +939,11 @@
int get length => _filtered.length;
Element operator [](int index) => _filtered[index];
Iterator<Element> get iterator => _filtered.iterator;
- List<Element> sublist(int start, [int end]) =>
- _filtered.sublist(start, end);
+ List<Element> sublist(int start, [int end]) => _filtered.sublist(start, end);
Iterable<Element> getRange(int start, int end) =>
- _filtered.getRange(start, end);
+ _filtered.getRange(start, end);
int indexOf(Element element, [int start = 0]) =>
- _filtered.indexOf(element, start);
+ _filtered.indexOf(element, start);
int lastIndexOf(Element element, [int start = null]) {
if (start == null) start = length - 1;
diff --git a/lib/dom_parsing.dart b/lib/dom_parsing.dart
index 527d9a6..5575dcd 100644
--- a/lib/dom_parsing.dart
+++ b/lib/dom_parsing.dart
@@ -9,13 +9,20 @@
class TreeVisitor {
visit(Node node) {
switch (node.nodeType) {
- case Node.ELEMENT_NODE: return visitElement(node);
- case Node.TEXT_NODE: return visitText(node);
- case Node.COMMENT_NODE: return visitComment(node);
- case Node.DOCUMENT_FRAGMENT_NODE: return visitDocumentFragment(node);
- case Node.DOCUMENT_NODE: return visitDocument(node);
- case Node.DOCUMENT_TYPE_NODE: return visitDocumentType(node);
- default: throw new UnsupportedError('DOM node type ${node.nodeType}');
+ case Node.ELEMENT_NODE:
+ return visitElement(node);
+ case Node.TEXT_NODE:
+ return visitText(node);
+ case Node.COMMENT_NODE:
+ return visitComment(node);
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ return visitDocumentFragment(node);
+ case Node.DOCUMENT_NODE:
+ return visitDocument(node);
+ case Node.DOCUMENT_TYPE_NODE:
+ return visitDocumentType(node);
+ default:
+ throw new UnsupportedError('DOM node type ${node.nodeType}');
}
}
@@ -92,8 +99,7 @@
_str.write(">");
return;
}
- _str.write(
- '</<code class="markup element-name">$tag</code>>');
+ _str.write('</<code class="markup element-name">$tag</code>>');
}
visitComment(Comment node) {
@@ -102,7 +108,6 @@
}
}
-
// TODO(jmesserly): reconcile this with dart:web htmlEscape.
// This one might be more useful, as it is HTML5 spec compliant.
/// Escapes [text] for use in the
@@ -128,11 +133,21 @@
var ch = text[i];
String replace = null;
switch (ch) {
- case '&': replace = '&'; break;
- case '\u00A0'/*NO-BREAK SPACE*/: replace = ' '; break;
- case '"': if (attributeMode) replace = '"'; break;
- case '<': if (!attributeMode) replace = '<'; break;
- case '>': if (!attributeMode) replace = '>'; break;
+ case '&':
+ replace = '&';
+ break;
+ case '\u00A0' /*NO-BREAK SPACE*/ :
+ replace = ' ';
+ break;
+ case '"':
+ if (attributeMode) replace = '"';
+ break;
+ case '<':
+ if (!attributeMode) replace = '<';
+ break;
+ case '>':
+ if (!attributeMode) replace = '>';
+ break;
}
if (replace != null) {
if (result == null) result = new StringBuffer(text.substring(0, i));
@@ -145,16 +160,27 @@
return result != null ? result.toString() : text;
}
-
/// Returns true if this tag name is a void element.
/// This method is useful to a pretty printer, because void elements must not
/// have an end tag.
/// See also: <http://dev.w3.org/html5/markup/syntax.html#void-elements>.
bool isVoidElement(String tagName) {
switch (tagName) {
- case "area": case "base": case "br": case "col": case "command":
- case "embed": case "hr": case "img": case "input": case "keygen":
- case "link": case "meta": case "param": case "source": case "track":
+ case "area":
+ case "base":
+ case "br":
+ case "col":
+ case "command":
+ case "embed":
+ case "hr":
+ case "img":
+ case "input":
+ case "keygen":
+ case "link":
+ case "meta":
+ case "param":
+ case "source":
+ case "track":
case "wbr":
return true;
}
diff --git a/lib/parser.dart b/lib/parser.dart
index ded6a74..a6618ab 100644
--- a/lib/parser.dart
+++ b/lib/parser.dart
@@ -36,14 +36,13 @@
/// [Node.sourceSpan] property will be `null`. When using [generateSpans] you
/// can additionally pass [sourceUrl] to indicate where the [input] was
/// extracted from.
-Document parse(input, {String encoding, bool generateSpans: false,
- String sourceUrl}) {
- var p = new HtmlParser(input, encoding: encoding,
- generateSpans: generateSpans, sourceUrl: sourceUrl);
+Document parse(input,
+ {String encoding, bool generateSpans: false, String sourceUrl}) {
+ var p = new HtmlParser(input,
+ encoding: encoding, generateSpans: generateSpans, sourceUrl: sourceUrl);
return p.parse();
}
-
/// Parse the [input] html5 document fragment into a tree. The [input] can be
/// a [String], [List<int>] of bytes or an [HtmlTokenizer]. The [container]
/// element can optionally be specified, otherwise it defaults to "div".
@@ -56,14 +55,13 @@
/// [Node.sourceSpan] property will be `null`. When using [generateSpans] you can
/// additionally pass [sourceUrl] to indicate where the [input] was extracted
/// from.
-DocumentFragment parseFragment(input, {String container: "div",
- String encoding, bool generateSpans: false, String sourceUrl}) {
- var p = new HtmlParser(input, encoding: encoding,
- generateSpans: generateSpans, sourceUrl: sourceUrl);
+DocumentFragment parseFragment(input, {String container: "div", String encoding,
+ bool generateSpans: false, String sourceUrl}) {
+ var p = new HtmlParser(input,
+ encoding: encoding, generateSpans: generateSpans, sourceUrl: sourceUrl);
return p.parseFragment(container);
}
-
/// Parser for HTML, which generates a tree structure from a stream of
/// (possibly malformed) characters.
class HtmlParser {
@@ -146,12 +144,15 @@
TreeBuilder tree})
: generateSpans = generateSpans,
tree = tree != null ? tree : new TreeBuilder(true),
- tokenizer = (input is HtmlTokenizer ? input :
- new HtmlTokenizer(input, encoding: encoding, parseMeta: parseMeta,
- lowercaseElementName: lowercaseElementName,
- lowercaseAttrName: lowercaseAttrName,
- generateSpans: generateSpans, sourceUrl: sourceUrl)) {
-
+ tokenizer = (input is HtmlTokenizer
+ ? input
+ : new HtmlTokenizer(input,
+ encoding: encoding,
+ parseMeta: parseMeta,
+ lowercaseElementName: lowercaseElementName,
+ lowercaseAttrName: lowercaseAttrName,
+ generateSpans: generateSpans,
+ sourceUrl: sourceUrl)) {
tokenizer.parser = this;
_initialPhase = new InitialPhase(this);
_beforeHtmlPhase = new BeforeHtmlPhase(this);
@@ -256,14 +257,14 @@
if (enc != null) enc = asciiUpper2Lower(enc);
return enc == "text/html" || enc == "application/xhtml+xml";
} else {
- return htmlIntegrationPointElements.contains(
- new Pair(element.namespaceUri, element.localName));
+ return htmlIntegrationPointElements
+ .contains(new Pair(element.namespaceUri, element.localName));
}
}
bool isMathMLTextIntegrationPoint(Element element) {
- return mathmlTextIntegrationPointElements.contains(
- new Pair(element.namespaceUri, element.localName));
+ return mathmlTextIntegrationPointElements
+ .contains(new Pair(element.namespaceUri, element.localName));
}
bool inForeignContent(Token token, int type) {
@@ -275,7 +276,7 @@
if (isMathMLTextIntegrationPoint(node)) {
if (type == TokenKind.startTag &&
(token as StartTagToken).name != "mglyph" &&
- (token as StartTagToken).name != "malignmark") {
+ (token as StartTagToken).name != "malignmark") {
return false;
}
if (type == TokenKind.characters || type == TokenKind.spaceCharacters) {
@@ -283,7 +284,8 @@
}
}
- if (node.localName == "annotation-xml" && type == TokenKind.startTag &&
+ if (node.localName == "annotation-xml" &&
+ type == TokenKind.startTag &&
(token as StartTagToken).name == "svg") {
return false;
}
@@ -343,8 +345,9 @@
if (token is StartTagToken) {
if (token.selfClosing && !token.selfClosingAcknowledged) {
- parseError(token.span, "non-void-element-with-trailing-solidus",
- {"name": token.name});
+ parseError(token.span, "non-void-element-with-trailing-solidus", {
+ "name": token.name
+ });
}
}
}
@@ -371,7 +374,6 @@
void parseError(SourceSpan span, String errorcode,
[Map datavars = const {}]) {
-
if (!generateSpans && span == null) {
span = _lastSpan;
}
@@ -390,68 +392,68 @@
void adjustSVGAttributes(StartTagToken token) {
final replacements = const {
- "attributename":"attributeName",
- "attributetype":"attributeType",
- "basefrequency":"baseFrequency",
- "baseprofile":"baseProfile",
- "calcmode":"calcMode",
- "clippathunits":"clipPathUnits",
- "contentscripttype":"contentScriptType",
- "contentstyletype":"contentStyleType",
- "diffuseconstant":"diffuseConstant",
- "edgemode":"edgeMode",
- "externalresourcesrequired":"externalResourcesRequired",
- "filterres":"filterRes",
- "filterunits":"filterUnits",
- "glyphref":"glyphRef",
- "gradienttransform":"gradientTransform",
- "gradientunits":"gradientUnits",
- "kernelmatrix":"kernelMatrix",
- "kernelunitlength":"kernelUnitLength",
- "keypoints":"keyPoints",
- "keysplines":"keySplines",
- "keytimes":"keyTimes",
- "lengthadjust":"lengthAdjust",
- "limitingconeangle":"limitingConeAngle",
- "markerheight":"markerHeight",
- "markerunits":"markerUnits",
- "markerwidth":"markerWidth",
- "maskcontentunits":"maskContentUnits",
- "maskunits":"maskUnits",
- "numoctaves":"numOctaves",
- "pathlength":"pathLength",
- "patterncontentunits":"patternContentUnits",
- "patterntransform":"patternTransform",
- "patternunits":"patternUnits",
- "pointsatx":"pointsAtX",
- "pointsaty":"pointsAtY",
- "pointsatz":"pointsAtZ",
- "preservealpha":"preserveAlpha",
- "preserveaspectratio":"preserveAspectRatio",
- "primitiveunits":"primitiveUnits",
- "refx":"refX",
- "refy":"refY",
- "repeatcount":"repeatCount",
- "repeatdur":"repeatDur",
- "requiredextensions":"requiredExtensions",
- "requiredfeatures":"requiredFeatures",
- "specularconstant":"specularConstant",
- "specularexponent":"specularExponent",
- "spreadmethod":"spreadMethod",
- "startoffset":"startOffset",
- "stddeviation":"stdDeviation",
- "stitchtiles":"stitchTiles",
- "surfacescale":"surfaceScale",
- "systemlanguage":"systemLanguage",
- "tablevalues":"tableValues",
- "targetx":"targetX",
- "targety":"targetY",
- "textlength":"textLength",
- "viewbox":"viewBox",
- "viewtarget":"viewTarget",
- "xchannelselector":"xChannelSelector",
- "ychannelselector":"yChannelSelector",
- "zoomandpan":"zoomAndPan"
+ "attributename": "attributeName",
+ "attributetype": "attributeType",
+ "basefrequency": "baseFrequency",
+ "baseprofile": "baseProfile",
+ "calcmode": "calcMode",
+ "clippathunits": "clipPathUnits",
+ "contentscripttype": "contentScriptType",
+ "contentstyletype": "contentStyleType",
+ "diffuseconstant": "diffuseConstant",
+ "edgemode": "edgeMode",
+ "externalresourcesrequired": "externalResourcesRequired",
+ "filterres": "filterRes",
+ "filterunits": "filterUnits",
+ "glyphref": "glyphRef",
+ "gradienttransform": "gradientTransform",
+ "gradientunits": "gradientUnits",
+ "kernelmatrix": "kernelMatrix",
+ "kernelunitlength": "kernelUnitLength",
+ "keypoints": "keyPoints",
+ "keysplines": "keySplines",
+ "keytimes": "keyTimes",
+ "lengthadjust": "lengthAdjust",
+ "limitingconeangle": "limitingConeAngle",
+ "markerheight": "markerHeight",
+ "markerunits": "markerUnits",
+ "markerwidth": "markerWidth",
+ "maskcontentunits": "maskContentUnits",
+ "maskunits": "maskUnits",
+ "numoctaves": "numOctaves",
+ "pathlength": "pathLength",
+ "patterncontentunits": "patternContentUnits",
+ "patterntransform": "patternTransform",
+ "patternunits": "patternUnits",
+ "pointsatx": "pointsAtX",
+ "pointsaty": "pointsAtY",
+ "pointsatz": "pointsAtZ",
+ "preservealpha": "preserveAlpha",
+ "preserveaspectratio": "preserveAspectRatio",
+ "primitiveunits": "primitiveUnits",
+ "refx": "refX",
+ "refy": "refY",
+ "repeatcount": "repeatCount",
+ "repeatdur": "repeatDur",
+ "requiredextensions": "requiredExtensions",
+ "requiredfeatures": "requiredFeatures",
+ "specularconstant": "specularConstant",
+ "specularexponent": "specularExponent",
+ "spreadmethod": "spreadMethod",
+ "startoffset": "startOffset",
+ "stddeviation": "stdDeviation",
+ "stitchtiles": "stitchTiles",
+ "surfacescale": "surfaceScale",
+ "systemlanguage": "systemLanguage",
+ "tablevalues": "tableValues",
+ "targetx": "targetX",
+ "targety": "targetY",
+ "textlength": "textLength",
+ "viewbox": "viewBox",
+ "viewtarget": "viewTarget",
+ "xchannelselector": "xChannelSelector",
+ "ychannelselector": "yChannelSelector",
+ "zoomandpan": "zoomAndPan"
};
for (var originalName in token.data.keys.toList()) {
var svgName = replacements[originalName];
@@ -465,10 +467,10 @@
// TODO(jmesserly): I don't like mixing non-string objects with strings in
// the Node.attributes Map. Is there another solution?
final replacements = const {
- "xlink:actuate": const AttributeName("xlink", "actuate",
- Namespaces.xlink),
- "xlink:arcrole": const AttributeName("xlink", "arcrole",
- Namespaces.xlink),
+ "xlink:actuate":
+ const AttributeName("xlink", "actuate", Namespaces.xlink),
+ "xlink:arcrole":
+ const AttributeName("xlink", "arcrole", Namespaces.xlink),
"xlink:href": const AttributeName("xlink", "href", Namespaces.xlink),
"xlink:role": const AttributeName("xlink", "role", Namespaces.xlink),
"xlink:show": const AttributeName("xlink", "show", Namespaces.xlink),
@@ -502,7 +504,10 @@
// Check for conditions that should only happen in the innerHTML
// case
switch (nodeName) {
- case "select": case "colgroup": case "head": case "html":
+ case "select":
+ case "colgroup":
+ case "head":
+ case "html":
assert(innerHTMLMode);
break;
}
@@ -510,20 +515,48 @@
continue;
}
switch (nodeName) {
- case "select": phase = _inSelectPhase; return;
- case "td": phase = _inCellPhase; return;
- case "th": phase = _inCellPhase; return;
- case "tr": phase = _inRowPhase; return;
- case "tbody": phase = _inTableBodyPhase; return;
- case "thead": phase = _inTableBodyPhase; return;
- case "tfoot": phase = _inTableBodyPhase; return;
- case "caption": phase = _inCaptionPhase; return;
- case "colgroup": phase = _inColumnGroupPhase; return;
- case "table": phase = _inTablePhase; return;
- case "head": phase = _inBodyPhase; return;
- case "body": phase = _inBodyPhase; return;
- case "frameset": phase = _inFramesetPhase; return;
- case "html": phase = _beforeHeadPhase; return;
+ case "select":
+ phase = _inSelectPhase;
+ return;
+ case "td":
+ phase = _inCellPhase;
+ return;
+ case "th":
+ phase = _inCellPhase;
+ return;
+ case "tr":
+ phase = _inRowPhase;
+ return;
+ case "tbody":
+ phase = _inTableBodyPhase;
+ return;
+ case "thead":
+ phase = _inTableBodyPhase;
+ return;
+ case "tfoot":
+ phase = _inTableBodyPhase;
+ return;
+ case "caption":
+ phase = _inCaptionPhase;
+ return;
+ case "colgroup":
+ phase = _inColumnGroupPhase;
+ return;
+ case "table":
+ phase = _inTablePhase;
+ return;
+ case "head":
+ phase = _inBodyPhase;
+ return;
+ case "body":
+ phase = _inBodyPhase;
+ return;
+ case "frameset":
+ phase = _inFramesetPhase;
+ return;
+ case "html":
+ phase = _beforeHeadPhase;
+ return;
}
}
phase = _inBodyPhase;
@@ -534,7 +567,7 @@
void parseRCDataRawtext(Token token, String contentType) {
assert(contentType == "RAWTEXT" || contentType == "RCDATA");
- var element = tree.insertElement(token);
+ tree.insertElement(token);
if (contentType == "RAWTEXT") {
tokenizer.state = tokenizer.rawtextState;
@@ -547,7 +580,6 @@
}
}
-
/// Base class for helper object that implements each phase of processing.
class Phase {
// Order should be (they can be omitted):
@@ -565,7 +597,9 @@
final TreeBuilder tree;
- Phase(HtmlParser parser) : parser = parser, tree = parser.tree;
+ Phase(HtmlParser parser)
+ : parser = parser,
+ tree = parser.tree;
bool processEOF() {
throw new UnimplementedError();
@@ -599,7 +633,7 @@
Token startTagHtml(StartTagToken token) {
if (parser.firstStartTag == false && token.name == "html") {
- parser.parseError(token.span, "non-html-root");
+ parser.parseError(token.span, "non-html-root");
}
// XXX Need a check here to see if the first start tag token emitted is
// this token... If it's not, invoke parser.parseError().
@@ -641,7 +675,8 @@
var systemId = token.systemId;
var correct = token.correct;
- if ((name != "html" || publicId != null ||
+ if ((name != "html" ||
+ publicId != null ||
systemId != null && systemId != "about:legacy-compat")) {
parser.parseError(token.span, "unknown-doctype");
}
@@ -656,80 +691,86 @@
publicId = asciiUpper2Lower(publicId);
}
- if (!correct || token.name != "html"
- || startsWithAny(publicId, const [
- "+//silmaril//dtd html pro v0r11 19970101//",
- "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
- "-//as//dtd html 3.0 aswedit + extensions//",
- "-//ietf//dtd html 2.0 level 1//",
- "-//ietf//dtd html 2.0 level 2//",
- "-//ietf//dtd html 2.0 strict level 1//",
- "-//ietf//dtd html 2.0 strict level 2//",
- "-//ietf//dtd html 2.0 strict//",
- "-//ietf//dtd html 2.0//",
- "-//ietf//dtd html 2.1e//",
- "-//ietf//dtd html 3.0//",
- "-//ietf//dtd html 3.2 final//",
- "-//ietf//dtd html 3.2//",
- "-//ietf//dtd html 3//",
- "-//ietf//dtd html level 0//",
- "-//ietf//dtd html level 1//",
- "-//ietf//dtd html level 2//",
- "-//ietf//dtd html level 3//",
- "-//ietf//dtd html strict level 0//",
- "-//ietf//dtd html strict level 1//",
- "-//ietf//dtd html strict level 2//",
- "-//ietf//dtd html strict level 3//",
- "-//ietf//dtd html strict//",
- "-//ietf//dtd html//",
- "-//metrius//dtd metrius presentational//",
- "-//microsoft//dtd internet explorer 2.0 html strict//",
- "-//microsoft//dtd internet explorer 2.0 html//",
- "-//microsoft//dtd internet explorer 2.0 tables//",
- "-//microsoft//dtd internet explorer 3.0 html strict//",
- "-//microsoft//dtd internet explorer 3.0 html//",
- "-//microsoft//dtd internet explorer 3.0 tables//",
- "-//netscape comm. corp.//dtd html//",
- "-//netscape comm. corp.//dtd strict html//",
- "-//o'reilly and associates//dtd html 2.0//",
- "-//o'reilly and associates//dtd html extended 1.0//",
- "-//o'reilly and associates//dtd html extended relaxed 1.0//",
- "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
- "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
- "-//spyglass//dtd html 2.0 extended//",
- "-//sq//dtd html 2.0 hotmetal + extensions//",
- "-//sun microsystems corp.//dtd hotjava html//",
- "-//sun microsystems corp.//dtd hotjava strict html//",
- "-//w3c//dtd html 3 1995-03-24//",
- "-//w3c//dtd html 3.2 draft//",
- "-//w3c//dtd html 3.2 final//",
- "-//w3c//dtd html 3.2//",
- "-//w3c//dtd html 3.2s draft//",
- "-//w3c//dtd html 4.0 frameset//",
- "-//w3c//dtd html 4.0 transitional//",
- "-//w3c//dtd html experimental 19960712//",
- "-//w3c//dtd html experimental 970421//",
- "-//w3c//dtd w3 html//",
- "-//w3o//dtd w3 html 3.0//",
- "-//webtechs//dtd mozilla html 2.0//",
- "-//webtechs//dtd mozilla html//"])
- || const ["-//w3o//dtd w3 html strict 3.0//en//",
- "-/w3c/dtd html 4.0 transitional/en",
- "html"].contains(publicId)
- || startsWithAny(publicId, const [
- "-//w3c//dtd html 4.01 frameset//",
- "-//w3c//dtd html 4.01 transitional//"]) && systemId == null
- || systemId != null && systemId.toLowerCase() ==
- "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {
-
+ if (!correct || token.name != "html" || startsWithAny(publicId, const [
+ "+//silmaril//dtd html pro v0r11 19970101//",
+ "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
+ "-//as//dtd html 3.0 aswedit + extensions//",
+ "-//ietf//dtd html 2.0 level 1//",
+ "-//ietf//dtd html 2.0 level 2//",
+ "-//ietf//dtd html 2.0 strict level 1//",
+ "-//ietf//dtd html 2.0 strict level 2//",
+ "-//ietf//dtd html 2.0 strict//",
+ "-//ietf//dtd html 2.0//",
+ "-//ietf//dtd html 2.1e//",
+ "-//ietf//dtd html 3.0//",
+ "-//ietf//dtd html 3.2 final//",
+ "-//ietf//dtd html 3.2//",
+ "-//ietf//dtd html 3//",
+ "-//ietf//dtd html level 0//",
+ "-//ietf//dtd html level 1//",
+ "-//ietf//dtd html level 2//",
+ "-//ietf//dtd html level 3//",
+ "-//ietf//dtd html strict level 0//",
+ "-//ietf//dtd html strict level 1//",
+ "-//ietf//dtd html strict level 2//",
+ "-//ietf//dtd html strict level 3//",
+ "-//ietf//dtd html strict//",
+ "-//ietf//dtd html//",
+ "-//metrius//dtd metrius presentational//",
+ "-//microsoft//dtd internet explorer 2.0 html strict//",
+ "-//microsoft//dtd internet explorer 2.0 html//",
+ "-//microsoft//dtd internet explorer 2.0 tables//",
+ "-//microsoft//dtd internet explorer 3.0 html strict//",
+ "-//microsoft//dtd internet explorer 3.0 html//",
+ "-//microsoft//dtd internet explorer 3.0 tables//",
+ "-//netscape comm. corp.//dtd html//",
+ "-//netscape comm. corp.//dtd strict html//",
+ "-//o'reilly and associates//dtd html 2.0//",
+ "-//o'reilly and associates//dtd html extended 1.0//",
+ "-//o'reilly and associates//dtd html extended relaxed 1.0//",
+ "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
+ "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
+ "-//spyglass//dtd html 2.0 extended//",
+ "-//sq//dtd html 2.0 hotmetal + extensions//",
+ "-//sun microsystems corp.//dtd hotjava html//",
+ "-//sun microsystems corp.//dtd hotjava strict html//",
+ "-//w3c//dtd html 3 1995-03-24//",
+ "-//w3c//dtd html 3.2 draft//",
+ "-//w3c//dtd html 3.2 final//",
+ "-//w3c//dtd html 3.2//",
+ "-//w3c//dtd html 3.2s draft//",
+ "-//w3c//dtd html 4.0 frameset//",
+ "-//w3c//dtd html 4.0 transitional//",
+ "-//w3c//dtd html experimental 19960712//",
+ "-//w3c//dtd html experimental 970421//",
+ "-//w3c//dtd w3 html//",
+ "-//w3o//dtd w3 html 3.0//",
+ "-//webtechs//dtd mozilla html 2.0//",
+ "-//webtechs//dtd mozilla html//"
+ ]) ||
+ const [
+ "-//w3o//dtd w3 html strict 3.0//en//",
+ "-/w3c/dtd html 4.0 transitional/en",
+ "html"
+ ].contains(publicId) ||
+ startsWithAny(publicId, const [
+ "-//w3c//dtd html 4.01 frameset//",
+ "-//w3c//dtd html 4.01 transitional//"
+ ]) &&
+ systemId == null ||
+ systemId != null &&
+ systemId.toLowerCase() ==
+ "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {
parser.compatMode = "quirks";
} else if (startsWithAny(publicId, const [
- "-//w3c//dtd xhtml 1.0 frameset//",
- "-//w3c//dtd xhtml 1.0 transitional//"])
- || startsWithAny(publicId, const [
- "-//w3c//dtd html 4.01 frameset//",
- "-//w3c//dtd html 4.01 transitional//"]) &&
- systemId != null) {
+ "-//w3c//dtd xhtml 1.0 frameset//",
+ "-//w3c//dtd xhtml 1.0 transitional//"
+ ]) ||
+ startsWithAny(publicId, const [
+ "-//w3c//dtd html 4.01 frameset//",
+ "-//w3c//dtd html 4.01 transitional//"
+ ]) &&
+ systemId != null) {
parser.compatMode = "limited quirks";
}
parser.phase = parser._beforeHtmlPhase;
@@ -748,15 +789,15 @@
}
Token processStartTag(StartTagToken token) {
- parser.parseError(token.span, "expected-doctype-but-got-start-tag",
- {"name": token.name});
+ parser.parseError(
+ token.span, "expected-doctype-but-got-start-tag", {"name": token.name});
anythingElse();
return token;
}
Token processEndTag(EndTagToken token) {
- parser.parseError(token.span, "expected-doctype-but-got-end-tag",
- {"name": token.name});
+ parser.parseError(
+ token.span, "expected-doctype-but-got-end-tag", {"name": token.name});
anythingElse();
return token;
}
@@ -768,7 +809,6 @@
}
}
-
class BeforeHtmlPhase extends Phase {
BeforeHtmlPhase(parser) : super(parser);
@@ -808,34 +848,43 @@
Token processEndTag(EndTagToken token) {
switch (token.name) {
- case "head": case "body": case "html": case "br":
+ case "head":
+ case "body":
+ case "html":
+ case "br":
insertHtmlElement();
return token;
default:
- parser.parseError(token.span, "unexpected-end-tag-before-html",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-end-tag-before-html", {"name": token.name});
return null;
}
}
}
-
class BeforeHeadPhase extends Phase {
BeforeHeadPhase(parser) : super(parser);
processStartTag(StartTagToken token) {
switch (token.name) {
- case 'html': return startTagHtml(token);
- case 'head': return startTagHead(token);
- default: return startTagOther(token);
+ case 'html':
+ return startTagHtml(token);
+ case 'head':
+ return startTagHead(token);
+ default:
+ return startTagOther(token);
}
}
processEndTag(EndTagToken token) {
switch (token.name) {
- case "head": case "body": case "html": case "br":
+ case "head":
+ case "body":
+ case "html":
+ case "br":
return endTagImplyHead(token);
- default: return endTagOther(token);
+ default:
+ return endTagOther(token);
}
}
@@ -874,8 +923,8 @@
}
void endTagOther(EndTagToken token) {
- parser.parseError(token.span, "end-tag-after-implied-root",
- {"name": token.name});
+ parser.parseError(
+ token.span, "end-tag-after-implied-root", {"name": token.name});
}
}
@@ -884,24 +933,41 @@
processStartTag(StartTagToken token) {
switch (token.name) {
- case "html": return startTagHtml(token);
- case "title": return startTagTitle(token);
- case "noscript": case "noframes": case "style":
+ case "html":
+ return startTagHtml(token);
+ case "title":
+ return startTagTitle(token);
+ case "noscript":
+ case "noframes":
+ case "style":
return startTagNoScriptNoFramesStyle(token);
- case "script": return startTagScript(token);
- case "base": case "basefont": case "bgsound": case "command": case "link":
+ case "script":
+ return startTagScript(token);
+ case "base":
+ case "basefont":
+ case "bgsound":
+ case "command":
+ case "link":
return startTagBaseLinkCommand(token);
- case "meta": return startTagMeta(token);
- case "head": return startTagHead(token);
- default: return startTagOther(token);
+ case "meta":
+ return startTagMeta(token);
+ case "head":
+ return startTagHead(token);
+ default:
+ return startTagOther(token);
}
}
processEndTag(EndTagToken token) {
switch (token.name) {
- case "head": return endTagHead(token);
- case "br": case "html": case "body": return endTagHtmlBodyBr(token);
- default: return endTagOther(token);
+ case "head":
+ return endTagHead(token);
+ case "br":
+ case "html":
+ case "body":
+ return endTagHtmlBodyBr(token);
+ default:
+ return endTagOther(token);
}
}
@@ -990,7 +1056,6 @@
}
}
-
// XXX If we implement a parser for which scripting is disabled we need to
// implement this phase.
//
@@ -1001,22 +1066,37 @@
processStartTag(StartTagToken token) {
switch (token.name) {
- case "html": return startTagHtml(token);
- case "body": return startTagBody(token);
- case "frameset": return startTagFrameset(token);
- case "base": case "basefont": case "bgsound": case "link": case "meta":
- case "noframes": case "script": case "style": case "title":
+ case "html":
+ return startTagHtml(token);
+ case "body":
+ return startTagBody(token);
+ case "frameset":
+ return startTagFrameset(token);
+ case "base":
+ case "basefont":
+ case "bgsound":
+ case "link":
+ case "meta":
+ case "noframes":
+ case "script":
+ case "style":
+ case "title":
return startTagFromHead(token);
- case "head": return startTagHead(token);
- default: return startTagOther(token);
+ case "head":
+ return startTagHead(token);
+ default:
+ return startTagOther(token);
}
}
processEndTag(EndTagToken token) {
switch (token.name) {
- case "body": case "html": case "br":
+ case "body":
+ case "html":
+ case "br":
return endTagHtmlBodyBr(token);
- default: return endTagOther(token);
+ default:
+ return endTagOther(token);
}
}
@@ -1046,8 +1126,9 @@
}
void startTagFromHead(StartTagToken token) {
- parser.parseError(token.span, "unexpected-start-tag-out-of-my-head",
- {"name": token.name});
+ parser.parseError(token.span, "unexpected-start-tag-out-of-my-head", {
+ "name": token.name
+ });
tree.openElements.add(tree.headPointer);
parser._inHeadPhase.processStartTag(token);
for (var node in tree.openElements.reversed) {
@@ -1096,48 +1177,101 @@
switch (token.name) {
case "html":
return startTagHtml(token);
- case "base": case "basefont": case "bgsound": case "command": case "link":
- case "meta": case "noframes": case "script": case "style": case "title":
+ case "base":
+ case "basefont":
+ case "bgsound":
+ case "command":
+ case "link":
+ case "meta":
+ case "noframes":
+ case "script":
+ case "style":
+ case "title":
return startTagProcessInHead(token);
case "body":
return startTagBody(token);
case "frameset":
return startTagFrameset(token);
- case "address": case "article": case "aside": case "blockquote":
- case "center": case "details": case "details": case "dir": case "div":
- case "dl": case "fieldset": case "figcaption": case "figure":
- case "footer": case "header": case "hgroup": case "menu": case "nav":
- case "ol": case "p": case "section": case "summary": case "ul":
+ case "address":
+ case "article":
+ case "aside":
+ case "blockquote":
+ case "center":
+ case "details":
+ case "details":
+ case "dir":
+ case "div":
+ case "dl":
+ case "fieldset":
+ case "figcaption":
+ case "figure":
+ case "footer":
+ case "header":
+ case "hgroup":
+ case "menu":
+ case "nav":
+ case "ol":
+ case "p":
+ case "section":
+ case "summary":
+ case "ul":
return startTagCloseP(token);
// headingElements
- case "h1": case "h2": case "h3": case "h4": case "h5": case "h6":
+ case "h1":
+ case "h2":
+ case "h3":
+ case "h4":
+ case "h5":
+ case "h6":
return startTagHeading(token);
- case "pre": case "listing":
+ case "pre":
+ case "listing":
return startTagPreListing(token);
case "form":
return startTagForm(token);
- case "li": case "dd": case "dt":
+ case "li":
+ case "dd":
+ case "dt":
return startTagListItem(token);
case "plaintext":
return startTagPlaintext(token);
- case "a": return startTagA(token);
- case "b": case "big": case "code": case "em": case "font": case "i":
- case "s": case "small": case "strike": case "strong": case "tt": case "u":
+ case "a":
+ return startTagA(token);
+ case "b":
+ case "big":
+ case "code":
+ case "em":
+ case "font":
+ case "i":
+ case "s":
+ case "small":
+ case "strike":
+ case "strong":
+ case "tt":
+ case "u":
return startTagFormatting(token);
case "nobr":
return startTagNobr(token);
case "button":
return startTagButton(token);
- case "applet": case "marquee": case "object":
+ case "applet":
+ case "marquee":
+ case "object":
return startTagAppletMarqueeObject(token);
case "xmp":
return startTagXmp(token);
case "table":
return startTagTable(token);
- case "area": case "br": case "embed": case "img": case "keygen":
+ case "area":
+ case "br":
+ case "embed":
+ case "img":
+ case "keygen":
case "wbr":
return startTagVoidFormatting(token);
- case "param": case "source": case "track":
+ case "param":
+ case "source":
+ case "track":
return startTagParamSource(token);
case "input":
return startTagInput(token);
@@ -1151,49 +1285,108 @@
return startTagTextarea(token);
case "iframe":
return startTagIFrame(token);
- case "noembed": case "noframes": case "noscript":
+ case "noembed":
+ case "noframes":
+ case "noscript":
return startTagRawtext(token);
case "select":
return startTagSelect(token);
- case "rp": case "rt":
+ case "rp":
+ case "rt":
return startTagRpRt(token);
- case "option": case "optgroup":
+ case "option":
+ case "optgroup":
return startTagOpt(token);
case "math":
return startTagMath(token);
case "svg":
return startTagSvg(token);
- case "caption": case "col": case "colgroup": case "frame": case "head":
- case "tbody": case "td": case "tfoot": case "th": case "thead": case "tr":
+ case "caption":
+ case "col":
+ case "colgroup":
+ case "frame":
+ case "head":
+ case "tbody":
+ case "td":
+ case "tfoot":
+ case "th":
+ case "thead":
+ case "tr":
return startTagMisplaced(token);
- default: return startTagOther(token);
+ default:
+ return startTagOther(token);
}
}
processEndTag(EndTagToken token) {
switch (token.name) {
- case "body": return endTagBody(token);
- case "html": return endTagHtml(token);
- case "address": case "article": case "aside": case "blockquote":
- case "center": case "details": case "dir": case "div": case "dl":
- case "fieldset": case "figcaption": case "figure": case "footer":
- case "header": case "hgroup": case "listing": case "menu": case "nav":
- case "ol": case "pre": case "section": case "summary": case "ul":
+ case "body":
+ return endTagBody(token);
+ case "html":
+ return endTagHtml(token);
+ case "address":
+ case "article":
+ case "aside":
+ case "blockquote":
+ case "center":
+ case "details":
+ case "dir":
+ case "div":
+ case "dl":
+ case "fieldset":
+ case "figcaption":
+ case "figure":
+ case "footer":
+ case "header":
+ case "hgroup":
+ case "listing":
+ case "menu":
+ case "nav":
+ case "ol":
+ case "pre":
+ case "section":
+ case "summary":
+ case "ul":
return endTagBlock(token);
- case "form": return endTagForm(token);
- case "p": return endTagP(token);
- case "dd": case "dt": case "li": return endTagListItem(token);
+ case "form":
+ return endTagForm(token);
+ case "p":
+ return endTagP(token);
+ case "dd":
+ case "dt":
+ case "li":
+ return endTagListItem(token);
// headingElements
- case "h1": case "h2": case "h3": case "h4": case "h5": case "h6":
+ case "h1":
+ case "h2":
+ case "h3":
+ case "h4":
+ case "h5":
+ case "h6":
return endTagHeading(token);
- case "a": case "b": case "big": case "code": case "em": case "font":
- case "i": case "nobr": case "s": case "small": case "strike":
- case "strong": case "tt": case "u":
+ case "a":
+ case "b":
+ case "big":
+ case "code":
+ case "em":
+ case "font":
+ case "i":
+ case "nobr":
+ case "s":
+ case "small":
+ case "strike":
+ case "strong":
+ case "tt":
+ case "u":
return endTagFormatting(token);
- case "applet": case "marquee": case "object":
+ case "applet":
+ case "marquee":
+ case "object":
return endTagAppletMarqueeObject(token);
- case "br": return endTagBr(token);
- default: return endTagOther(token);
+ case "br":
+ return endTagBr(token);
+ default:
+ return endTagOther(token);
}
}
@@ -1238,8 +1431,17 @@
bool processEOF() {
for (var node in tree.openElements.reversed) {
switch (node.localName) {
- case "dd": case "dt": case "li": case "p": case "tbody": case "td":
- case "tfoot": case "th": case "thead": case "tr": case "body":
+ case "dd":
+ case "dt":
+ case "li":
+ case "p":
+ case "tbody":
+ case "td":
+ case "tfoot":
+ case "th":
+ case "thead":
+ case "tr":
+ case "body":
case "html":
continue;
}
@@ -1257,8 +1459,8 @@
dropNewline = false;
if (data.startsWith("\n")) {
var lastOpen = tree.openElements.last;
- if (const ["pre", "listing", "textarea"].contains(lastOpen.localName)
- && !lastOpen.hasContent()) {
+ if (const ["pre", "listing", "textarea"].contains(lastOpen.localName) &&
+ !lastOpen.hasContent()) {
data = data.substring(1);
}
}
@@ -1297,8 +1499,8 @@
void startTagBody(StartTagToken token) {
parser.parseError(token.span, "unexpected-start-tag", {"name": "body"});
- if (tree.openElements.length == 1
- || tree.openElements[1].localName != "body") {
+ if (tree.openElements.length == 1 ||
+ tree.openElements[1].localName != "body") {
assert(parser.innerHTMLMode);
} else {
parser.framesetOK = false;
@@ -1356,9 +1558,11 @@
void startTagListItem(StartTagToken token) {
parser.framesetOK = false;
- final stopNamesMap = const {"li": const ["li"],
- "dt": const ["dt", "dd"],
- "dd": const ["dt", "dd"]};
+ final stopNamesMap = const {
+ "li": const ["li"],
+ "dt": const ["dt", "dd"],
+ "dd": const ["dt", "dd"]
+ };
var stopNames = stopNamesMap[token.name];
for (var node in tree.openElements.reversed) {
if (stopNames.contains(node.localName)) {
@@ -1391,8 +1595,8 @@
endTagP(new EndTagToken("p"));
}
if (headingElements.contains(tree.openElements.last.localName)) {
- parser.parseError(token.span, "unexpected-start-tag",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-start-tag", {"name": token.name});
tree.openElements.removeLast();
}
tree.insertElement(token);
@@ -1401,8 +1605,10 @@
void startTagA(StartTagToken token) {
var afeAElement = tree.elementInActiveFormattingElements("a");
if (afeAElement != null) {
- parser.parseError(token.span, "unexpected-start-tag-implies-end-tag",
- {"startName": "a", "endName": "a"});
+ parser.parseError(token.span, "unexpected-start-tag-implies-end-tag", {
+ "startName": "a",
+ "endName": "a"
+ });
endTagFormatting(new EndTagToken("a"));
tree.openElements.remove(afeAElement);
tree.activeFormattingElements.remove(afeAElement);
@@ -1419,8 +1625,10 @@
void startTagNobr(StartTagToken token) {
tree.reconstructActiveFormattingElements();
if (tree.elementInScope("nobr")) {
- parser.parseError(token.span, "unexpected-start-tag-implies-end-tag",
- {"startName": "nobr", "endName": "nobr"});
+ parser.parseError(token.span, "unexpected-start-tag-implies-end-tag", {
+ "startName": "nobr",
+ "endName": "nobr"
+ });
processEndTag(new EndTagToken("nobr"));
// XXX Need tests that trigger the following
tree.reconstructActiveFormattingElements();
@@ -1430,8 +1638,10 @@
Token startTagButton(StartTagToken token) {
if (tree.elementInScope("button")) {
- parser.parseError(token.span, "unexpected-start-tag-implies-end-tag",
- {"startName": "button", "endName": "button"});
+ parser.parseError(token.span, "unexpected-start-tag-implies-end-tag", {
+ "startName": "button",
+ "endName": "button"
+ });
processEndTag(new EndTagToken("button"));
return token;
} else {
@@ -1504,10 +1714,12 @@
void startTagImage(StartTagToken token) {
// No really...
- parser.parseError(token.span, "unexpected-start-tag-treated-as",
- {"originalName": "image", "newName": "img"});
- processStartTag(new StartTagToken("img", data: token.data,
- selfClosing: token.selfClosing));
+ parser.parseError(token.span, "unexpected-start-tag-treated-as", {
+ "originalName": "image",
+ "newName": "img"
+ });
+ processStartTag(new StartTagToken("img",
+ data: token.data, selfClosing: token.selfClosing));
}
void startTagIsIndex(StartTagToken token) {
@@ -1533,8 +1745,8 @@
attributes.remove('action');
attributes.remove('prompt');
attributes["name"] = "isindex";
- processStartTag(new StartTagToken("input",
- data: attributes, selfClosing: token.selfClosing));
+ processStartTag(new StartTagToken(
+ "input", data: attributes, selfClosing: token.selfClosing));
processEndTag(new EndTagToken("label"));
processStartTag(new StartTagToken("hr", data: {}));
processEndTag(new EndTagToken("form"));
@@ -1627,8 +1839,8 @@
/// "option", "optgroup", "tbody", "td", "tfoot", "th", "thead",
/// "tr", "noscript"
void startTagMisplaced(StartTagToken token) {
- parser.parseError(token.span, "unexpected-start-tag-ignored",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-start-tag-ignored", {"name": token.name});
}
Token startTagOther(StartTagToken token) {
@@ -1658,14 +1870,29 @@
} else if (tree.openElements.last.localName != "body") {
for (Element node in slice(tree.openElements, 2)) {
switch (node.localName) {
- case "dd": case "dt": case "li": case "optgroup": case "option":
- case "p": case "rp": case "rt": case "tbody": case "td": case "tfoot":
- case "th": case "thead": case "tr": case "body": case "html":
+ case "dd":
+ case "dt":
+ case "li":
+ case "optgroup":
+ case "option":
+ case "p":
+ case "rp":
+ case "rt":
+ case "tbody":
+ case "td":
+ case "tfoot":
+ case "th":
+ case "thead":
+ case "tr":
+ case "body":
+ case "html":
continue;
}
// Not sure this is the correct name for the parse error
- parser.parseError(token.span, "expected-one-end-tag-but-got-another",
- {"gotName": "body", "expectedName": node.localName});
+ parser.parseError(token.span, "expected-one-end-tag-but-got-another", {
+ "gotName": "body",
+ "expectedName": node.localName
+ });
break;
}
}
@@ -1706,7 +1933,8 @@
} else {
tree.generateImpliedEndTags();
if (tree.openElements.last != node) {
- parser.parseError(token.span, "end-tag-too-early-ignored", {"name": "form"});
+ parser.parseError(
+ token.span, "end-tag-too-early-ignored", {"name": "form"});
}
tree.openElements.remove(node);
}
@@ -1724,7 +1952,8 @@
} else {
tree.generateImpliedEndTags(token.name);
if (tree.openElements.last.localName != token.name) {
- parser.parseError(token.span, "end-tag-too-early", {"name": token.name});
+ parser.parseError(
+ token.span, "end-tag-too-early", {"name": token.name});
}
popOpenElementsUntil(token.name);
}
@@ -1764,26 +1993,26 @@
outerLoopCounter += 1;
// Step 1 paragraph 1
- var formattingElement = tree.elementInActiveFormattingElements(
- token.name);
+ var formattingElement =
+ tree.elementInActiveFormattingElements(token.name);
if (formattingElement == null ||
(tree.openElements.contains(formattingElement) &&
- !tree.elementInScope(formattingElement.localName))) {
- parser.parseError(token.span, "adoption-agency-1.1",
- {"name": token.name});
+ !tree.elementInScope(formattingElement.localName))) {
+ parser.parseError(
+ token.span, "adoption-agency-1.1", {"name": token.name});
return;
- // Step 1 paragraph 2
+ // Step 1 paragraph 2
} else if (!tree.openElements.contains(formattingElement)) {
- parser.parseError(token.span, "adoption-agency-1.2",
- {"name": token.name});
+ parser.parseError(
+ token.span, "adoption-agency-1.2", {"name": token.name});
tree.activeFormattingElements.remove(formattingElement);
return;
}
// Step 1 paragraph 3
if (formattingElement != tree.openElements.last) {
- parser.parseError(token.span, "adoption-agency-1.3",
- {"name": token.name});
+ parser.parseError(
+ token.span, "adoption-agency-1.3", {"name": token.name});
}
// Step 2
@@ -1867,8 +2096,13 @@
lastNode.parentNode.nodes.remove(lastNode);
}
- if (const ["table", "tbody", "tfoot", "thead", "tr"].contains(
- commonAncestor.localName)) {
+ if (const [
+ "table",
+ "tbody",
+ "tfoot",
+ "thead",
+ "tr"
+ ].contains(commonAncestor.localName)) {
var nodePos = tree.getTableMisnestedNodePosition();
nodePos[0].insertBefore(lastNode, nodePos[1]);
} else {
@@ -1910,8 +2144,10 @@
}
void endTagBr(EndTagToken token) {
- parser.parseError(token.span, "unexpected-end-tag-treated-as",
- {"originalName": "br", "newName": "br element"});
+ parser.parseError(token.span, "unexpected-end-tag-treated-as", {
+ "originalName": "br",
+ "newName": "br element"
+ });
tree.reconstructActiveFormattingElements();
tree.insertElement(new StartTagToken("br", data: {}));
tree.openElements.removeLast();
@@ -1922,15 +2158,15 @@
if (node.localName == token.name) {
tree.generateImpliedEndTags(token.name);
if (tree.openElements.last.localName != token.name) {
- parser.parseError(token.span, "unexpected-end-tag",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-end-tag", {"name": token.name});
}
while (tree.openElements.removeLast() != node);
break;
} else {
if (specialElements.contains(getElementNameTuple(node))) {
- parser.parseError(token.span, "unexpected-end-tag",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-end-tag", {"name": token.name});
break;
}
}
@@ -1938,12 +2174,13 @@
}
}
-
class TextPhase extends Phase {
TextPhase(parser) : super(parser);
// "Tried to process start tag %s in RCDATA/RAWTEXT mode"%token.name
- processStartTag(StartTagToken token) { assert(false); }
+ processStartTag(StartTagToken token) {
+ assert(false);
+ }
processEndTag(EndTagToken token) {
if (token.name == 'script') return endTagScript(token);
@@ -1973,7 +2210,7 @@
}
void endTagOther(EndTagToken token) {
- var node = tree.openElements.removeLast();
+ tree.openElements.removeLast();
parser.phase = parser.originalPhase;
}
}
@@ -1984,27 +2221,54 @@
processStartTag(StartTagToken token) {
switch (token.name) {
- case "html": return startTagHtml(token);
- case "caption": return startTagCaption(token);
- case "colgroup": return startTagColgroup(token);
- case "col": return startTagCol(token);
- case "tbody": case "tfoot": case "thead": return startTagRowGroup(token);
- case "td": case "th": case "tr": return startTagImplyTbody(token);
- case "table": return startTagTable(token);
- case "style": case "script": return startTagStyleScript(token);
- case "input": return startTagInput(token);
- case "form": return startTagForm(token);
- default: return startTagOther(token);
+ case "html":
+ return startTagHtml(token);
+ case "caption":
+ return startTagCaption(token);
+ case "colgroup":
+ return startTagColgroup(token);
+ case "col":
+ return startTagCol(token);
+ case "tbody":
+ case "tfoot":
+ case "thead":
+ return startTagRowGroup(token);
+ case "td":
+ case "th":
+ case "tr":
+ return startTagImplyTbody(token);
+ case "table":
+ return startTagTable(token);
+ case "style":
+ case "script":
+ return startTagStyleScript(token);
+ case "input":
+ return startTagInput(token);
+ case "form":
+ return startTagForm(token);
+ default:
+ return startTagOther(token);
}
}
processEndTag(EndTagToken token) {
switch (token.name) {
- case "table": return endTagTable(token);
- case "body": case "caption": case "col": case "colgroup": case "html":
- case "tbody": case "td": case "tfoot": case "th": case "thead": case "tr":
+ case "table":
+ return endTagTable(token);
+ case "body":
+ case "caption":
+ case "col":
+ case "colgroup":
+ case "html":
+ case "tbody":
+ case "td":
+ case "tfoot":
+ case "th":
+ case "thead":
+ case "tr":
return endTagIgnore(token);
- default: return endTagOther(token);
+ default:
+ return endTagOther(token);
}
}
@@ -2012,7 +2276,7 @@
void clearStackToTableContext() {
// "clear the stack back to a table context"
while (tree.openElements.last.localName != "table" &&
- tree.openElements.last.localName != "html") {
+ tree.openElements.last.localName != "html") {
//parser.parseError(token.span, "unexpected-implied-end-tag-in-table",
// {"name": tree.openElements.last.name})
tree.openElements.removeLast();
@@ -2086,8 +2350,10 @@
}
Token startTagTable(StartTagToken token) {
- parser.parseError(token.span, "unexpected-start-tag-implies-end-tag",
- {"startName": "table", "endName": "table"});
+ parser.parseError(token.span, "unexpected-start-tag-implies-end-tag", {
+ "startName": "table",
+ "endName": "table"
+ });
parser.phase.processEndTag(new EndTagToken("table"));
if (!parser.innerHTMLMode) {
return token;
@@ -2120,8 +2386,9 @@
}
void startTagOther(StartTagToken token) {
- parser.parseError(token.span, "unexpected-start-tag-implies-table-voodoo",
- {"name": token.name});
+ parser.parseError(token.span, "unexpected-start-tag-implies-table-voodoo", {
+ "name": token.name
+ });
// Do the table magic!
tree.insertFromTable = true;
parser._inBodyPhase.processStartTag(token);
@@ -2133,8 +2400,10 @@
tree.generateImpliedEndTags();
var last = tree.openElements.last;
if (last.localName != "table") {
- parser.parseError(token.span, "end-tag-too-early-named",
- {"gotName": "table", "expectedName": last.localName});
+ parser.parseError(token.span, "end-tag-too-early-named", {
+ "gotName": "table",
+ "expectedName": last.localName
+ });
}
while (tree.openElements.last.localName != "table") {
tree.openElements.removeLast();
@@ -2153,8 +2422,9 @@
}
void endTagOther(EndTagToken token) {
- parser.parseError(token.span, "unexpected-end-tag-implies-table-voodoo",
- {"name": token.name});
+ parser.parseError(token.span, "unexpected-end-tag-implies-table-voodoo", {
+ "name": token.name
+ });
// Do the table magic!
tree.insertFromTable = true;
parser._inBodyPhase.processEndTag(token);
@@ -2229,29 +2499,48 @@
}
}
-
class InCaptionPhase extends Phase {
// http://www.whatwg.org/specs/web-apps/current-work///in-caption
InCaptionPhase(parser) : super(parser);
processStartTag(StartTagToken token) {
switch (token.name) {
- case "html": return startTagHtml(token);
- case "caption": case "col": case "colgroup": case "tbody": case "td":
- case "tfoot": case "th": case "thead": case "tr":
+ case "html":
+ return startTagHtml(token);
+ case "caption":
+ case "col":
+ case "colgroup":
+ case "tbody":
+ case "td":
+ case "tfoot":
+ case "th":
+ case "thead":
+ case "tr":
return startTagTableElement(token);
- default: return startTagOther(token);
+ default:
+ return startTagOther(token);
}
}
processEndTag(EndTagToken token) {
switch (token.name) {
- case "caption": return endTagCaption(token);
- case "table": return endTagTable(token);
- case "body": case "col": case "colgroup": case "html": case "tbody":
- case "td": case "tfoot": case "th": case "thead": case "tr":
+ case "caption":
+ return endTagCaption(token);
+ case "table":
+ return endTagTable(token);
+ case "body":
+ case "col":
+ case "colgroup":
+ case "html":
+ case "tbody":
+ case "td":
+ case "tfoot":
+ case "th":
+ case "thead":
+ case "tr":
return endTagIgnore(token);
- default: return endTagOther(token);
+ default:
+ return endTagOther(token);
}
}
@@ -2288,9 +2577,10 @@
// AT this code is quite similar to endTagTable in "InTable"
tree.generateImpliedEndTags();
if (tree.openElements.last.localName != "caption") {
- parser.parseError(token.span, "expected-one-end-tag-but-got-another",
- {"gotName": "caption",
- "expectedName": tree.openElements.last.localName});
+ parser.parseError(token.span, "expected-one-end-tag-but-got-another", {
+ "gotName": "caption",
+ "expectedName": tree.openElements.last.localName
+ });
}
while (tree.openElements.last.localName != "caption") {
tree.openElements.removeLast();
@@ -2324,24 +2614,29 @@
}
}
-
class InColumnGroupPhase extends Phase {
// http://www.whatwg.org/specs/web-apps/current-work///in-column
InColumnGroupPhase(parser) : super(parser);
processStartTag(StartTagToken token) {
switch (token.name) {
- case "html": return startTagHtml(token);
- case "col": return startTagCol(token);
- default: return startTagOther(token);
+ case "html":
+ return startTagHtml(token);
+ case "col":
+ return startTagCol(token);
+ default:
+ return startTagOther(token);
}
}
processEndTag(EndTagToken token) {
switch (token.name) {
- case "colgroup": return endTagColgroup(token);
- case "col": return endTagCol(token);
- default: return endTagOther(token);
+ case "colgroup":
+ return endTagColgroup(token);
+ case "col":
+ return endTagCol(token);
+ default:
+ return endTagOther(token);
}
}
@@ -2399,32 +2694,50 @@
}
}
-
class InTableBodyPhase extends Phase {
// http://www.whatwg.org/specs/web-apps/current-work///in-table0
InTableBodyPhase(parser) : super(parser);
processStartTag(StartTagToken token) {
switch (token.name) {
- case "html": return startTagHtml(token);
- case "tr": return startTagTr(token);
- case "td": case "th": return startTagTableCell(token);
- case "caption": case "col": case "colgroup": case "tbody": case "tfoot":
+ case "html":
+ return startTagHtml(token);
+ case "tr":
+ return startTagTr(token);
+ case "td":
+ case "th":
+ return startTagTableCell(token);
+ case "caption":
+ case "col":
+ case "colgroup":
+ case "tbody":
+ case "tfoot":
case "thead":
return startTagTableOther(token);
- default: return startTagOther(token);
+ default:
+ return startTagOther(token);
}
}
processEndTag(EndTagToken token) {
switch (token.name) {
- case "tbody": case "tfoot": case "thead":
+ case "tbody":
+ case "tfoot":
+ case "thead":
return endTagTableRowGroup(token);
- case "table": return endTagTable(token);
- case "body": case "caption": case "col": case "colgroup": case "html":
- case "td": case "th": case "tr":
+ case "table":
+ return endTagTable(token);
+ case "body":
+ case "caption":
+ case "col":
+ case "colgroup":
+ case "html":
+ case "td":
+ case "th":
+ case "tr":
return endTagIgnore(token);
- default: return endTagOther(token);
+ default:
+ return endTagOther(token);
}
}
@@ -2462,8 +2775,8 @@
}
Token startTagTableCell(StartTagToken token) {
- parser.parseError(token.span, "unexpected-cell-in-table-body",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-cell-in-table-body", {"name": token.name});
startTagTr(new StartTagToken("tr", data: {}));
return token;
}
@@ -2480,8 +2793,8 @@
tree.openElements.removeLast();
parser.phase = parser._inTablePhase;
} else {
- parser.parseError(token.span, "unexpected-end-tag-in-table-body",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-end-tag-in-table-body", {"name": token.name});
}
}
@@ -2502,8 +2815,8 @@
}
void endTagIgnore(EndTagToken token) {
- parser.parseError(token.span, "unexpected-end-tag-in-table-body",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-end-tag-in-table-body", {"name": token.name});
}
Token endTagOther(EndTagToken token) {
@@ -2511,32 +2824,50 @@
}
}
-
class InRowPhase extends Phase {
// http://www.whatwg.org/specs/web-apps/current-work///in-row
InRowPhase(parser) : super(parser);
processStartTag(StartTagToken token) {
switch (token.name) {
- case "html": return startTagHtml(token);
- case "td": case "th": return startTagTableCell(token);
- case "caption": case "col": case "colgroup": case "tbody": case "tfoot":
- case "thead": case "tr":
+ case "html":
+ return startTagHtml(token);
+ case "td":
+ case "th":
+ return startTagTableCell(token);
+ case "caption":
+ case "col":
+ case "colgroup":
+ case "tbody":
+ case "tfoot":
+ case "thead":
+ case "tr":
return startTagTableOther(token);
- default: return startTagOther(token);
+ default:
+ return startTagOther(token);
}
}
processEndTag(EndTagToken token) {
switch (token.name) {
- case "tr": return endTagTr(token);
- case "table": return endTagTable(token);
- case "tbody": case "tfoot": case "thead":
+ case "tr":
+ return endTagTr(token);
+ case "table":
+ return endTagTable(token);
+ case "tbody":
+ case "tfoot":
+ case "thead":
return endTagTableRowGroup(token);
- case "body": case "caption": case "col": case "colgroup": case "html":
- case "td": case "th":
+ case "body":
+ case "caption":
+ case "col":
+ case "colgroup":
+ case "html":
+ case "td":
+ case "th":
return endTagIgnore(token);
- default: return endTagOther(token);
+ default:
+ return endTagOther(token);
}
}
@@ -2547,8 +2878,9 @@
if (last.localName == "tr" || last.localName == "html") break;
parser.parseError(last.sourceSpan,
- "unexpected-implied-end-tag-in-table-row",
- {"name": tree.openElements.last.localName});
+ "unexpected-implied-end-tag-in-table-row", {
+ "name": tree.openElements.last.localName
+ });
tree.openElements.removeLast();
}
}
@@ -2620,8 +2952,8 @@
}
void endTagIgnore(EndTagToken token) {
- parser.parseError(token.span, "unexpected-end-tag-in-table-row",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-end-tag-in-table-row", {"name": token.name});
}
Token endTagOther(EndTagToken token) {
@@ -2635,23 +2967,42 @@
processStartTag(StartTagToken token) {
switch (token.name) {
- case "html": return startTagHtml(token);
- case "caption": case "col": case "colgroup": case "tbody": case "td":
- case "tfoot": case "th": case "thead": case "tr":
+ case "html":
+ return startTagHtml(token);
+ case "caption":
+ case "col":
+ case "colgroup":
+ case "tbody":
+ case "td":
+ case "tfoot":
+ case "th":
+ case "thead":
+ case "tr":
return startTagTableOther(token);
- default: return startTagOther(token);
+ default:
+ return startTagOther(token);
}
}
processEndTag(EndTagToken token) {
switch (token.name) {
- case "td": case "th":
+ case "td":
+ case "th":
return endTagTableCell(token);
- case "body": case "caption": case "col": case "colgroup": case "html":
+ case "body":
+ case "caption":
+ case "col":
+ case "colgroup":
+ case "html":
return endTagIgnore(token);
- case "table": case "tbody": case "tfoot": case "thead": case "tr":
+ case "table":
+ case "tbody":
+ case "tfoot":
+ case "thead":
+ case "tr":
return endTagImply(token);
- default: return endTagOther(token);
+ default:
+ return endTagOther(token);
}
}
@@ -2676,7 +3027,7 @@
Token startTagTableOther(StartTagToken token) {
if (tree.elementInScope("td", variant: "table") ||
- tree.elementInScope("th", variant: "table")) {
+ tree.elementInScope("th", variant: "table")) {
closeCell();
return token;
} else {
@@ -2695,8 +3046,8 @@
if (tree.elementInScope(token.name, variant: "table")) {
tree.generateImpliedEndTags(token.name);
if (tree.openElements.last.localName != token.name) {
- parser.parseError(token.span, "unexpected-cell-end-tag",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-cell-end-tag", {"name": token.name});
popOpenElementsUntil(token.name);
} else {
tree.openElements.removeLast();
@@ -2733,23 +3084,35 @@
processStartTag(StartTagToken token) {
switch (token.name) {
- case "html": return startTagHtml(token);
- case "option": return startTagOption(token);
- case "optgroup": return startTagOptgroup(token);
- case "select": return startTagSelect(token);
- case "input": case "keygen": case "textarea":
+ case "html":
+ return startTagHtml(token);
+ case "option":
+ return startTagOption(token);
+ case "optgroup":
+ return startTagOptgroup(token);
+ case "select":
+ return startTagSelect(token);
+ case "input":
+ case "keygen":
+ case "textarea":
return startTagInput(token);
- case "script": return startTagScript(token);
- default: return startTagOther(token);
+ case "script":
+ return startTagScript(token);
+ default:
+ return startTagOther(token);
}
}
processEndTag(EndTagToken token) {
switch (token.name) {
- case "option": return endTagOption(token);
- case "optgroup": return endTagOptgroup(token);
- case "select": return endTagSelect(token);
- default: return endTagOther(token);
+ case "option":
+ return endTagOption(token);
+ case "optgroup":
+ return endTagOptgroup(token);
+ case "select":
+ return endTagSelect(token);
+ default:
+ return endTagOther(token);
}
}
@@ -2811,8 +3174,8 @@
}
Token startTagOther(StartTagToken token) {
- parser.parseError(token.span, "unexpected-start-tag-in-select",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-start-tag-in-select", {"name": token.name});
return null;
}
@@ -2820,24 +3183,25 @@
if (tree.openElements.last.localName == "option") {
tree.openElements.removeLast();
} else {
- parser.parseError(token.span, "unexpected-end-tag-in-select",
- {"name": "option"});
+ parser.parseError(
+ token.span, "unexpected-end-tag-in-select", {"name": "option"});
}
}
void endTagOptgroup(EndTagToken token) {
// </optgroup> implicitly closes <option>
if (tree.openElements.last.localName == "option" &&
- tree.openElements[tree.openElements.length - 2].localName == "optgroup") {
+ tree.openElements[tree.openElements.length - 2].localName ==
+ "optgroup") {
tree.openElements.removeLast();
}
// It also closes </optgroup>
if (tree.openElements.last.localName == "optgroup") {
tree.openElements.removeLast();
- // But nothing else
+ // But nothing else
} else {
- parser.parseError(token.span, "unexpected-end-tag-in-select",
- {"name": "optgroup"});
+ parser.parseError(
+ token.span, "unexpected-end-tag-in-select", {"name": "optgroup"});
}
}
@@ -2853,30 +3217,43 @@
}
void endTagOther(EndTagToken token) {
- parser.parseError(token.span, "unexpected-end-tag-in-select",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-end-tag-in-select", {"name": token.name});
}
}
-
class InSelectInTablePhase extends Phase {
InSelectInTablePhase(parser) : super(parser);
processStartTag(StartTagToken token) {
switch (token.name) {
- case "caption": case "table": case "tbody": case "tfoot": case "thead":
- case "tr": case "td": case "th":
+ case "caption":
+ case "table":
+ case "tbody":
+ case "tfoot":
+ case "thead":
+ case "tr":
+ case "td":
+ case "th":
return startTagTable(token);
- default: return startTagOther(token);
+ default:
+ return startTagOther(token);
}
}
processEndTag(EndTagToken token) {
switch (token.name) {
- case "caption": case "table": case "tbody": case "tfoot": case "thead":
- case "tr": case "td": case "th":
+ case "caption":
+ case "table":
+ case "tbody":
+ case "tfoot":
+ case "thead":
+ case "tr":
+ case "td":
+ case "th":
return endTagTable(token);
- default: return endTagOther(token);
+ default:
+ return endTagOther(token);
}
}
@@ -2891,8 +3268,9 @@
Token startTagTable(StartTagToken token) {
parser.parseError(token.span,
- "unexpected-table-element-start-tag-in-select-in-table",
- {"name": token.name});
+ "unexpected-table-element-start-tag-in-select-in-table", {
+ "name": token.name
+ });
endTagOther(new EndTagToken("select"));
return token;
}
@@ -2903,8 +3281,9 @@
Token endTagTable(EndTagToken token) {
parser.parseError(token.span,
- "unexpected-table-element-end-tag-in-select-in-table",
- {"name": token.name});
+ "unexpected-table-element-end-tag-in-select-in-table", {
+ "name": token.name
+ });
if (tree.elementInScope(token.name, variant: "table")) {
endTagOther(new EndTagToken("select"));
return token;
@@ -2917,57 +3296,95 @@
}
}
-
class InForeignContentPhase extends Phase {
// TODO(jmesserly): this is sorted so we could binary search.
static const breakoutElements = const [
- 'b', 'big', 'blockquote', 'body', 'br','center', 'code', 'dd', 'div', 'dl',
- 'dt', 'em', 'embed', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'i',
- 'img', 'li', 'listing', 'menu', 'meta', 'nobr', 'ol', 'p', 'pre', 'ruby',
- 's', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'tt', 'u',
- 'ul', 'var'
+ 'b',
+ 'big',
+ 'blockquote',
+ 'body',
+ 'br',
+ 'center',
+ 'code',
+ 'dd',
+ 'div',
+ 'dl',
+ 'dt',
+ 'em',
+ 'embed',
+ 'h1',
+ 'h2',
+ 'h3',
+ 'h4',
+ 'h5',
+ 'h6',
+ 'head',
+ 'hr',
+ 'i',
+ 'img',
+ 'li',
+ 'listing',
+ 'menu',
+ 'meta',
+ 'nobr',
+ 'ol',
+ 'p',
+ 'pre',
+ 'ruby',
+ 's',
+ 'small',
+ 'span',
+ 'strike',
+ 'strong',
+ 'sub',
+ 'sup',
+ 'table',
+ 'tt',
+ 'u',
+ 'ul',
+ 'var'
];
InForeignContentPhase(parser) : super(parser);
void adjustSVGTagNames(token) {
final replacements = const {
- "altglyph":"altGlyph",
- "altglyphdef":"altGlyphDef",
- "altglyphitem":"altGlyphItem",
- "animatecolor":"animateColor",
- "animatemotion":"animateMotion",
- "animatetransform":"animateTransform",
- "clippath":"clipPath",
- "feblend":"feBlend",
- "fecolormatrix":"feColorMatrix",
- "fecomponenttransfer":"feComponentTransfer",
- "fecomposite":"feComposite",
- "feconvolvematrix":"feConvolveMatrix",
- "fediffuselighting":"feDiffuseLighting",
- "fedisplacementmap":"feDisplacementMap",
- "fedistantlight":"feDistantLight",
- "feflood":"feFlood",
- "fefunca":"feFuncA",
- "fefuncb":"feFuncB",
- "fefuncg":"feFuncG",
- "fefuncr":"feFuncR",
- "fegaussianblur":"feGaussianBlur",
- "feimage":"feImage",
- "femerge":"feMerge",
- "femergenode":"feMergeNode",
- "femorphology":"feMorphology",
- "feoffset":"feOffset",
- "fepointlight":"fePointLight",
- "fespecularlighting":"feSpecularLighting",
- "fespotlight":"feSpotLight",
- "fetile":"feTile",
- "feturbulence":"feTurbulence",
- "foreignobject":"foreignObject",
- "glyphref":"glyphRef",
- "lineargradient":"linearGradient",
- "radialgradient":"radialGradient",
- "textpath":"textPath"
+ "altglyph": "altGlyph",
+ "altglyphdef": "altGlyphDef",
+ "altglyphitem": "altGlyphItem",
+ "animatecolor": "animateColor",
+ "animatemotion": "animateMotion",
+ "animatetransform": "animateTransform",
+ "clippath": "clipPath",
+ "feblend": "feBlend",
+ "fecolormatrix": "feColorMatrix",
+ "fecomponenttransfer": "feComponentTransfer",
+ "fecomposite": "feComposite",
+ "feconvolvematrix": "feConvolveMatrix",
+ "fediffuselighting": "feDiffuseLighting",
+ "fedisplacementmap": "feDisplacementMap",
+ "fedistantlight": "feDistantLight",
+ "feflood": "feFlood",
+ "fefunca": "feFuncA",
+ "fefuncb": "feFuncB",
+ "fefuncg": "feFuncG",
+ "fefuncr": "feFuncR",
+ "fegaussianblur": "feGaussianBlur",
+ "feimage": "feImage",
+ "femerge": "feMerge",
+ "femergenode": "feMergeNode",
+ "femorphology": "feMorphology",
+ "feoffset": "feOffset",
+ "fepointlight": "fePointLight",
+ "fespecularlighting": "feSpecularLighting",
+ "fespotlight": "feSpotLight",
+ "fetile": "feTile",
+ "feturbulence": "feTurbulence",
+ "foreignobject": "foreignObject",
+ "glyphref": "glyphRef",
+ "lineargradient": "linearGradient",
+ "radialgradient": "radialGradient",
+ "textpath": "textPath"
};
var replace = replacements[token.name];
@@ -2989,20 +3406,17 @@
var currentNode = tree.openElements.last;
if (breakoutElements.contains(token.name) ||
(token.name == "font" &&
- (token.data.containsKey("color") ||
- token.data.containsKey("face") ||
- token.data.containsKey("size")))) {
-
+ (token.data.containsKey("color") ||
+ token.data.containsKey("face") ||
+ token.data.containsKey("size")))) {
parser.parseError(token.span,
"unexpected-html-element-in-foreign-content", {'name': token.name});
- while (tree.openElements.last.namespaceUri !=
- tree.defaultNamespace &&
- !parser.isHTMLIntegrationPoint(tree.openElements.last) &&
- !parser.isMathMLTextIntegrationPoint(tree.openElements.last)) {
+ while (tree.openElements.last.namespaceUri != tree.defaultNamespace &&
+ !parser.isHTMLIntegrationPoint(tree.openElements.last) &&
+ !parser.isMathMLTextIntegrationPoint(tree.openElements.last)) {
tree.openElements.removeLast();
}
return token;
-
} else {
if (currentNode.namespaceUri == Namespaces.mathml) {
parser.adjustMathMLAttributes(token);
@@ -3057,7 +3471,6 @@
}
}
-
class AfterBodyPhase extends Phase {
AfterBodyPhase(parser) : super(parser);
@@ -3092,8 +3505,8 @@
}
Token startTagOther(StartTagToken token) {
- parser.parseError(token.span, "unexpected-start-tag-after-body",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-start-tag-after-body", {"name": token.name});
parser.phase = parser._inBodyPhase;
return token;
}
@@ -3107,8 +3520,8 @@
}
Token endTagOther(EndTagToken token) {
- parser.parseError(token.span, "unexpected-end-tag-after-body",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-end-tag-after-body", {"name": token.name});
parser.phase = parser._inBodyPhase;
return token;
}
@@ -3120,18 +3533,25 @@
processStartTag(StartTagToken token) {
switch (token.name) {
- case "html": return startTagHtml(token);
- case "frameset": return startTagFrameset(token);
- case "frame": return startTagFrame(token);
- case "noframes": return startTagNoframes(token);
- default: return startTagOther(token);
+ case "html":
+ return startTagHtml(token);
+ case "frameset":
+ return startTagFrameset(token);
+ case "frame":
+ return startTagFrame(token);
+ case "noframes":
+ return startTagNoframes(token);
+ default:
+ return startTagOther(token);
}
}
processEndTag(EndTagToken token) {
switch (token.name) {
- case "frameset": return endTagFrameset(token);
- default: return endTagOther(token);
+ case "frameset":
+ return endTagFrameset(token);
+ default:
+ return endTagOther(token);
}
}
@@ -3164,16 +3584,16 @@
}
Token startTagOther(StartTagToken token) {
- parser.parseError(token.span, "unexpected-start-tag-in-frameset",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-start-tag-in-frameset", {"name": token.name});
return null;
}
void endTagFrameset(EndTagToken token) {
if (tree.openElements.last.localName == "html") {
// innerHTML case
- parser.parseError(token.span,
- "unexpected-frameset-in-frameset-innerhtml");
+ parser.parseError(
+ token.span, "unexpected-frameset-in-frameset-innerhtml");
} else {
tree.openElements.removeLast();
}
@@ -3186,28 +3606,32 @@
}
void endTagOther(EndTagToken token) {
- parser.parseError(token.span, "unexpected-end-tag-in-frameset",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-end-tag-in-frameset", {"name": token.name});
}
}
-
class AfterFramesetPhase extends Phase {
// http://www.whatwg.org/specs/web-apps/current-work///after3
AfterFramesetPhase(parser) : super(parser);
processStartTag(StartTagToken token) {
switch (token.name) {
- case "html": return startTagHtml(token);
- case "noframes": return startTagNoframes(token);
- default: return startTagOther(token);
+ case "html":
+ return startTagHtml(token);
+ case "noframes":
+ return startTagNoframes(token);
+ default:
+ return startTagOther(token);
}
}
processEndTag(EndTagToken token) {
switch (token.name) {
- case "html": return endTagHtml(token);
- default: return endTagOther(token);
+ case "html":
+ return endTagHtml(token);
+ default:
+ return endTagOther(token);
}
}
@@ -3224,8 +3648,9 @@
}
void startTagOther(StartTagToken token) {
- parser.parseError(token.span, "unexpected-start-tag-after-frameset",
- {"name": token.name});
+ parser.parseError(token.span, "unexpected-start-tag-after-frameset", {
+ "name": token.name
+ });
}
void endTagHtml(EndTagToken token) {
@@ -3233,12 +3658,11 @@
}
void endTagOther(EndTagToken token) {
- parser.parseError(token.span, "unexpected-end-tag-after-frameset",
- {"name": token.name});
+ parser.parseError(
+ token.span, "unexpected-end-tag-after-frameset", {"name": token.name});
}
}
-
class AfterAfterBodyPhase extends Phase {
AfterAfterBodyPhase(parser) : super(parser);
@@ -3269,15 +3693,15 @@
}
Token startTagOther(StartTagToken token) {
- parser.parseError(token.span, "expected-eof-but-got-start-tag",
- {"name": token.name});
+ parser.parseError(
+ token.span, "expected-eof-but-got-start-tag", {"name": token.name});
parser.phase = parser._inBodyPhase;
return token;
}
Token processEndTag(EndTagToken token) {
- parser.parseError(token.span, "expected-eof-but-got-end-tag",
- {"name": token.name});
+ parser.parseError(
+ token.span, "expected-eof-but-got-end-tag", {"name": token.name});
parser.phase = parser._inBodyPhase;
return token;
}
@@ -3288,9 +3712,12 @@
processStartTag(StartTagToken token) {
switch (token.name) {
- case "html": return startTagHtml(token);
- case "noframes": return startTagNoFrames(token);
- default: return startTagOther(token);
+ case "html":
+ return startTagHtml(token);
+ case "noframes":
+ return startTagNoFrames(token);
+ default:
+ return startTagOther(token);
}
}
@@ -3319,18 +3746,17 @@
}
void startTagOther(StartTagToken token) {
- parser.parseError(token.span, "expected-eof-but-got-start-tag",
- {"name": token.name});
+ parser.parseError(
+ token.span, "expected-eof-but-got-start-tag", {"name": token.name});
}
Token processEndTag(EndTagToken token) {
- parser.parseError(token.span, "expected-eof-but-got-end-tag",
- {"name": token.name});
+ parser.parseError(
+ token.span, "expected-eof-but-got-end-tag", {"name": token.name});
return null;
}
}
-
/// Error in parsed document.
class ParseError implements SourceSpanException {
final String errorCode;
@@ -3357,7 +3783,6 @@
}
}
-
/// Convenience function to get the pair of namespace and localName.
Pair<String, String> getElementNameTuple(Element e) {
var ns = e.namespaceUri;
diff --git a/lib/src/char_encodings.dart b/lib/src/char_encodings.dart
index 9c04999..5ddf727 100644
--- a/lib/src/char_encodings.dart
+++ b/lib/src/char_encodings.dart
@@ -21,8 +21,8 @@
/// Decodes the [bytes] with the provided [encoding] and returns an iterable for
/// the codepoints. Supports the major unicode encodings as well as ascii and
/// and windows-1252 encodings.
-Iterable<int> decodeBytes(String encoding, List<int> bytes,
- [int offset = 0, int length,
+Iterable<int> decodeBytes(String encoding, List<int> bytes, [int offset = 0,
+ int length,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
if (length == null) length = bytes.length;
final replace = replacementCodepoint;
@@ -72,7 +72,6 @@
}
}
-
// TODO(jmesserly): use dart:utf once http://dartbug.com/6476 is fixed.
/// Returns the code points for the [input]. This works like [String.charCodes]
/// but it decodes UTF-16 surrogate pairs.
@@ -95,7 +94,6 @@
return newCodes;
}
-
/// Decodes [windows-1252](http://en.wikipedia.org/wiki/Windows-1252) bytes as
/// an iterable. Thus, the consumer can only convert as much of the input as
/// needed. Set the [replacementCharacter] to null to throw an [ArgumentError]
@@ -103,11 +101,10 @@
IterableWindows1252Decoder decodeWindows1252AsIterable(List<int> bytes,
[int offset = 0, int length,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
- return new IterableWindows1252Decoder(bytes, offset, length,
- replacementCodepoint);
+ return new IterableWindows1252Decoder(
+ bytes, offset, length, replacementCodepoint);
}
-
/// Return type of [decodeWindows1252AsIterable] and variants. The Iterable type
/// provides an iterator on demand and the iterator will only translate bytes
/// as requested by the user of the iterator. (Note: results are not cached.)
@@ -125,7 +122,6 @@
new Windows1252Decoder(bytes, offset, length, replacementCodepoint);
}
-
/// Provides an iterator of Unicode codepoints from windows-1252 encoded bytes.
/// The parameters can set an offset into a list of bytes (as int), limit the
/// length of the values to be decoded, and override the default Unicode
@@ -156,33 +152,60 @@
// TODO(jmesserly): this is duplicating entitiesWindows1252 and
// replacementCharacters from constants.dart
switch (char) {
- case 0x80: return 0x20AC; // EURO SIGN
- case 0x82: return 0x201A; // SINGLE LOW-9 QUOTATION MARK
- case 0x83: return 0x0192; // LATIN SMALL LETTER F WITH HOOK
- case 0x84: return 0x201E; // DOUBLE LOW-9 QUOTATION MARK
- case 0x85: return 0x2026; // HORIZONTAL ELLIPSIS
- case 0x86: return 0x2020; // DAGGER
- case 0x87: return 0x2021; // DOUBLE DAGGER
- case 0x88: return 0x02C6; // MODIFIER LETTER CIRCUMFLEX ACCENT
- case 0x89: return 0x2030; // PER MILLE SIGN
- case 0x8A: return 0x0160; // LATIN CAPITAL LETTER S WITH CARON
- case 0x8B: return 0x2039; // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
- case 0x8C: return 0x0152; // LATIN CAPITAL LIGATURE OE
- case 0x8E: return 0x017D; // LATIN CAPITAL LETTER Z WITH CARON
- case 0x91: return 0x2018; // LEFT SINGLE QUOTATION MARK
- case 0x92: return 0x2019; // RIGHT SINGLE QUOTATION MARK
- case 0x93: return 0x201C; // LEFT DOUBLE QUOTATION MARK
- case 0x94: return 0x201D; // RIGHT DOUBLE QUOTATION MARK
- case 0x95: return 0x2022; // BULLET
- case 0x96: return 0x2013; // EN DASH
- case 0x97: return 0x2014; // EM DASH
- case 0x98: return 0x02DC; // SMALL TILDE
- case 0x99: return 0x2122; // TRADE MARK SIGN
- case 0x9A: return 0x0161; // LATIN SMALL LETTER S WITH CARON
- case 0x9B: return 0x203A; // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
- case 0x9C: return 0x0153; // LATIN SMALL LIGATURE OE
- case 0x9E: return 0x017E; // LATIN SMALL LETTER Z WITH CARON
- case 0x9F: return 0x0178; // LATIN CAPITAL LETTER Y WITH DIAERESIS
+ case 0x80:
+ return 0x20AC; // EURO SIGN
+ case 0x82:
+ return 0x201A; // SINGLE LOW-9 QUOTATION MARK
+ case 0x83:
+ return 0x0192; // LATIN SMALL LETTER F WITH HOOK
+ case 0x84:
+ return 0x201E; // DOUBLE LOW-9 QUOTATION MARK
+ case 0x85:
+ return 0x2026; // HORIZONTAL ELLIPSIS
+ case 0x86:
+ return 0x2020; // DAGGER
+ case 0x87:
+ return 0x2021; // DOUBLE DAGGER
+ case 0x88:
+ return 0x02C6; // MODIFIER LETTER CIRCUMFLEX ACCENT
+ case 0x89:
+ return 0x2030; // PER MILLE SIGN
+ case 0x8A:
+ return 0x0160; // LATIN CAPITAL LETTER S WITH CARON
+ case 0x8B:
+ return 0x2039; // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ case 0x8C:
+ return 0x0152; // LATIN CAPITAL LIGATURE OE
+ case 0x8E:
+ return 0x017D; // LATIN CAPITAL LETTER Z WITH CARON
+ case 0x91:
+ return 0x2018; // LEFT SINGLE QUOTATION MARK
+ case 0x92:
+ return 0x2019; // RIGHT SINGLE QUOTATION MARK
+ case 0x93:
+ return 0x201C; // LEFT DOUBLE QUOTATION MARK
+ case 0x94:
+ return 0x201D; // RIGHT DOUBLE QUOTATION MARK
+ case 0x95:
+ return 0x2022; // BULLET
+ case 0x96:
+ return 0x2013; // EN DASH
+ case 0x97:
+ return 0x2014; // EM DASH
+ case 0x98:
+ return 0x02DC; // SMALL TILDE
+ case 0x99:
+ return 0x2122; // TRADE MARK SIGN
+ case 0x9A:
+ return 0x0161; // LATIN SMALL LETTER S WITH CARON
+ case 0x9B:
+ return 0x203A; // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ case 0x9C:
+ return 0x0153; // LATIN SMALL LIGATURE OE
+ case 0x9E:
+ return 0x017E; // LATIN SMALL LETTER Z WITH CARON
+ case 0x9F:
+ return 0x0178; // LATIN CAPITAL LETTER Y WITH DIAERESIS
case 0x81:
case 0x8D:
diff --git a/lib/src/constants.dart b/lib/src/constants.dart
index 0fd9e12..e85e43a 100644
--- a/lib/src/constants.dart
+++ b/lib/src/constants.dart
@@ -20,283 +20,219 @@
/// style string formatting, as implemented by [formatStr]. That function only
/// supports the subset of format functionality used here.
const Map<String, String> errorMessages = const {
- "null-character":
- "Null character in input stream, replaced with U+FFFD.",
- "invalid-codepoint":
- "Invalid codepoint in stream.",
- "incorrectly-placed-solidus":
- "Solidus (/) incorrectly placed in tag.",
+ "null-character": "Null character in input stream, replaced with U+FFFD.",
+ "invalid-codepoint": "Invalid codepoint in stream.",
+ "incorrectly-placed-solidus": "Solidus (/) incorrectly placed in tag.",
"incorrect-cr-newline-entity":
- "Incorrect CR newline entity, replaced with LF.",
+ "Incorrect CR newline entity, replaced with LF.",
"illegal-windows-1252-entity":
- "Entity used with illegal number (windows-1252 reference).",
+ "Entity used with illegal number (windows-1252 reference).",
"cant-convert-numeric-entity":
- "Numeric entity couldn't be converted to character "
- "(codepoint U+%(charAsInt)08x).",
+ "Numeric entity couldn't be converted to character "
+ "(codepoint U+%(charAsInt)08x).",
"illegal-codepoint-for-numeric-entity":
- "Numeric entity represents an illegal codepoint: "
- "U+%(charAsInt)08x.",
- "numeric-entity-without-semicolon":
- "Numeric entity didn't end with ';'.",
+ "Numeric entity represents an illegal codepoint: "
+ "U+%(charAsInt)08x.",
+ "numeric-entity-without-semicolon": "Numeric entity didn't end with ';'.",
"expected-numeric-entity-but-got-eof":
- "Numeric entity expected. Got end of file instead.",
- "expected-numeric-entity":
- "Numeric entity expected but none found.",
- "named-entity-without-semicolon":
- "Named entity didn't end with ';'.",
- "expected-named-entity":
- "Named entity expected. Got none.",
- "attributes-in-end-tag":
- "End tag contains unexpected attributes.",
+ "Numeric entity expected. Got end of file instead.",
+ "expected-numeric-entity": "Numeric entity expected but none found.",
+ "named-entity-without-semicolon": "Named entity didn't end with ';'.",
+ "expected-named-entity": "Named entity expected. Got none.",
+ "attributes-in-end-tag": "End tag contains unexpected attributes.",
'self-closing-flag-on-end-tag':
"End tag contains unexpected self-closing flag.",
"expected-tag-name-but-got-right-bracket":
- "Expected tag name. Got '>' instead.",
+ "Expected tag name. Got '>' instead.",
"expected-tag-name-but-got-question-mark":
- "Expected tag name. Got '?' instead. (HTML doesn't "
- "support processing instructions.)",
- "expected-tag-name":
- "Expected tag name. Got something else instead",
+ "Expected tag name. Got '?' instead. (HTML doesn't "
+ "support processing instructions.)",
+ "expected-tag-name": "Expected tag name. Got something else instead",
"expected-closing-tag-but-got-right-bracket":
- "Expected closing tag. Got '>' instead. Ignoring '</>'.",
+ "Expected closing tag. Got '>' instead. Ignoring '</>'.",
"expected-closing-tag-but-got-eof":
- "Expected closing tag. Unexpected end of file.",
+ "Expected closing tag. Unexpected end of file.",
"expected-closing-tag-but-got-char":
- "Expected closing tag. Unexpected character '%(data)s' found.",
- "eof-in-tag-name":
- "Unexpected end of file in the tag name.",
+ "Expected closing tag. Unexpected character '%(data)s' found.",
+ "eof-in-tag-name": "Unexpected end of file in the tag name.",
"expected-attribute-name-but-got-eof":
- "Unexpected end of file. Expected attribute name instead.",
- "eof-in-attribute-name":
- "Unexpected end of file in attribute name.",
- "invalid-character-in-attribute-name":
- "Invalid character in attribute name",
- "duplicate-attribute":
- "Dropped duplicate attribute on tag.",
+ "Unexpected end of file. Expected attribute name instead.",
+ "eof-in-attribute-name": "Unexpected end of file in attribute name.",
+ "invalid-character-in-attribute-name": "Invalid character in attribute name",
+ "duplicate-attribute": "Dropped duplicate attribute on tag.",
"expected-end-of-tag-name-but-got-eof":
- "Unexpected end of file. Expected = or end of tag.",
+ "Unexpected end of file. Expected = or end of tag.",
"expected-attribute-value-but-got-eof":
- "Unexpected end of file. Expected attribute value.",
+ "Unexpected end of file. Expected attribute value.",
"expected-attribute-value-but-got-right-bracket":
- "Expected attribute value. Got '>' instead.",
- 'equals-in-unquoted-attribute-value':
- "Unexpected = in unquoted attribute",
+ "Expected attribute value. Got '>' instead.",
+ 'equals-in-unquoted-attribute-value': "Unexpected = in unquoted attribute",
'unexpected-character-in-unquoted-attribute-value':
"Unexpected character in unquoted attribute",
"invalid-character-after-attribute-name":
- "Unexpected character after attribute name.",
+ "Unexpected character after attribute name.",
"unexpected-character-after-attribute-value":
- "Unexpected character after attribute value.",
+ "Unexpected character after attribute value.",
"eof-in-attribute-value-double-quote":
- "Unexpected end of file in attribute value (\".",
+ "Unexpected end of file in attribute value (\".",
"eof-in-attribute-value-single-quote":
- "Unexpected end of file in attribute value (').",
+ "Unexpected end of file in attribute value (').",
"eof-in-attribute-value-no-quotes":
- "Unexpected end of file in attribute value.",
+ "Unexpected end of file in attribute value.",
"unexpected-EOF-after-solidus-in-tag":
"Unexpected end of file in tag. Expected >",
"unexpected-character-after-soldius-in-tag":
"Unexpected character after / in tag. Expected >",
- "expected-dashes-or-doctype":
- "Expected '--' or 'DOCTYPE'. Not found.",
+ "expected-dashes-or-doctype": "Expected '--' or 'DOCTYPE'. Not found.",
"unexpected-bang-after-double-dash-in-comment":
"Unexpected ! after -- in comment",
"unexpected-space-after-double-dash-in-comment":
"Unexpected space after -- in comment",
- "incorrect-comment":
- "Incorrect comment.",
- "eof-in-comment":
- "Unexpected end of file in comment.",
- "eof-in-comment-end-dash":
- "Unexpected end of file in comment (-)",
+ "incorrect-comment": "Incorrect comment.",
+ "eof-in-comment": "Unexpected end of file in comment.",
+ "eof-in-comment-end-dash": "Unexpected end of file in comment (-)",
"unexpected-dash-after-double-dash-in-comment":
- "Unexpected '-' after '--' found in comment.",
- "eof-in-comment-double-dash":
- "Unexpected end of file in comment (--).",
- "eof-in-comment-end-space-state":
- "Unexpected end of file in comment.",
- "eof-in-comment-end-bang-state":
- "Unexpected end of file in comment.",
- "unexpected-char-in-comment":
- "Unexpected character in comment found.",
- "need-space-after-doctype":
- "No space after literal string 'DOCTYPE'.",
+ "Unexpected '-' after '--' found in comment.",
+ "eof-in-comment-double-dash": "Unexpected end of file in comment (--).",
+ "eof-in-comment-end-space-state": "Unexpected end of file in comment.",
+ "eof-in-comment-end-bang-state": "Unexpected end of file in comment.",
+ "unexpected-char-in-comment": "Unexpected character in comment found.",
+ "need-space-after-doctype": "No space after literal string 'DOCTYPE'.",
"expected-doctype-name-but-got-right-bracket":
- "Unexpected > character. Expected DOCTYPE name.",
+ "Unexpected > character. Expected DOCTYPE name.",
"expected-doctype-name-but-got-eof":
- "Unexpected end of file. Expected DOCTYPE name.",
- "eof-in-doctype-name":
- "Unexpected end of file in DOCTYPE name.",
- "eof-in-doctype":
- "Unexpected end of file in DOCTYPE.",
+ "Unexpected end of file. Expected DOCTYPE name.",
+ "eof-in-doctype-name": "Unexpected end of file in DOCTYPE name.",
+ "eof-in-doctype": "Unexpected end of file in DOCTYPE.",
"expected-space-or-right-bracket-in-doctype":
- "Expected space or '>'. Got '%(data)s'",
- "unexpected-end-of-doctype":
- "Unexpected end of DOCTYPE.",
- "unexpected-char-in-doctype":
- "Unexpected character in DOCTYPE.",
- "eof-in-innerhtml":
- "XXX innerHTML EOF",
- "unexpected-doctype":
- "Unexpected DOCTYPE. Ignored.",
- "non-html-root":
- "html needs to be the first start tag.",
- "expected-doctype-but-got-eof":
- "Unexpected End of file. Expected DOCTYPE.",
- "unknown-doctype":
- "Erroneous DOCTYPE.",
+ "Expected space or '>'. Got '%(data)s'",
+ "unexpected-end-of-doctype": "Unexpected end of DOCTYPE.",
+ "unexpected-char-in-doctype": "Unexpected character in DOCTYPE.",
+ "eof-in-innerhtml": "XXX innerHTML EOF",
+ "unexpected-doctype": "Unexpected DOCTYPE. Ignored.",
+ "non-html-root": "html needs to be the first start tag.",
+ "expected-doctype-but-got-eof": "Unexpected End of file. Expected DOCTYPE.",
+ "unknown-doctype": "Erroneous DOCTYPE.",
"expected-doctype-but-got-chars":
- "Unexpected non-space characters. Expected DOCTYPE.",
+ "Unexpected non-space characters. Expected DOCTYPE.",
"expected-doctype-but-got-start-tag":
- "Unexpected start tag (%(name)s). Expected DOCTYPE.",
+ "Unexpected start tag (%(name)s). Expected DOCTYPE.",
"expected-doctype-but-got-end-tag":
- "Unexpected end tag (%(name)s). Expected DOCTYPE.",
+ "Unexpected end tag (%(name)s). Expected DOCTYPE.",
"end-tag-after-implied-root":
- "Unexpected end tag (%(name)s) after the (implied) root element.",
+ "Unexpected end tag (%(name)s) after the (implied) root element.",
"expected-named-closing-tag-but-got-eof":
- "Unexpected end of file. Expected end tag (%(name)s).",
+ "Unexpected end of file. Expected end tag (%(name)s).",
"two-heads-are-not-better-than-one":
- "Unexpected start tag head in existing head. Ignored.",
- "unexpected-end-tag":
- "Unexpected end tag (%(name)s). Ignored.",
+ "Unexpected start tag head in existing head. Ignored.",
+ "unexpected-end-tag": "Unexpected end tag (%(name)s). Ignored.",
"unexpected-start-tag-out-of-my-head":
- "Unexpected start tag (%(name)s) that can be in head. Moved.",
- "unexpected-start-tag":
- "Unexpected start tag (%(name)s).",
- "missing-end-tag":
- "Missing end tag (%(name)s).",
- "missing-end-tags":
- "Missing end tags (%(name)s).",
+ "Unexpected start tag (%(name)s) that can be in head. Moved.",
+ "unexpected-start-tag": "Unexpected start tag (%(name)s).",
+ "missing-end-tag": "Missing end tag (%(name)s).",
+ "missing-end-tags": "Missing end tags (%(name)s).",
"unexpected-start-tag-implies-end-tag":
- "Unexpected start tag (%(startName)s) "
- "implies end tag (%(endName)s).",
+ "Unexpected start tag (%(startName)s) "
+ "implies end tag (%(endName)s).",
"unexpected-start-tag-treated-as":
- "Unexpected start tag (%(originalName)s). Treated as %(newName)s.",
- "deprecated-tag":
- "Unexpected start tag %(name)s. Don't use it!",
- "unexpected-start-tag-ignored":
- "Unexpected start tag %(name)s. Ignored.",
- "expected-one-end-tag-but-got-another":
- "Unexpected end tag (%(gotName)s). "
- "Missing end tag (%(expectedName)s).",
+ "Unexpected start tag (%(originalName)s). Treated as %(newName)s.",
+ "deprecated-tag": "Unexpected start tag %(name)s. Don't use it!",
+ "unexpected-start-tag-ignored": "Unexpected start tag %(name)s. Ignored.",
+ "expected-one-end-tag-but-got-another": "Unexpected end tag (%(gotName)s). "
+ "Missing end tag (%(expectedName)s).",
"end-tag-too-early":
- "End tag (%(name)s) seen too early. Expected other end tag.",
+ "End tag (%(name)s) seen too early. Expected other end tag.",
"end-tag-too-early-named":
- "Unexpected end tag (%(gotName)s). Expected end tag (%(expectedName)s).",
- "end-tag-too-early-ignored":
- "End tag (%(name)s) seen too early. Ignored.",
- "adoption-agency-1.1":
- "End tag (%(name)s) violates step 1, "
- "paragraph 1 of the adoption agency algorithm.",
- "adoption-agency-1.2":
- "End tag (%(name)s) violates step 1, "
- "paragraph 2 of the adoption agency algorithm.",
- "adoption-agency-1.3":
- "End tag (%(name)s) violates step 1, "
- "paragraph 3 of the adoption agency algorithm.",
+ "Unexpected end tag (%(gotName)s). Expected end tag (%(expectedName)s).",
+ "end-tag-too-early-ignored": "End tag (%(name)s) seen too early. Ignored.",
+ "adoption-agency-1.1": "End tag (%(name)s) violates step 1, "
+ "paragraph 1 of the adoption agency algorithm.",
+ "adoption-agency-1.2": "End tag (%(name)s) violates step 1, "
+ "paragraph 2 of the adoption agency algorithm.",
+ "adoption-agency-1.3": "End tag (%(name)s) violates step 1, "
+ "paragraph 3 of the adoption agency algorithm.",
"unexpected-end-tag-treated-as":
- "Unexpected end tag (%(originalName)s). Treated as %(newName)s.",
- "no-end-tag":
- "This element (%(name)s) has no end tag.",
+ "Unexpected end tag (%(originalName)s). Treated as %(newName)s.",
+ "no-end-tag": "This element (%(name)s) has no end tag.",
"unexpected-implied-end-tag-in-table":
- "Unexpected implied end tag (%(name)s) in the table phase.",
+ "Unexpected implied end tag (%(name)s) in the table phase.",
"unexpected-implied-end-tag-in-table-body":
- "Unexpected implied end tag (%(name)s) in the table body phase.",
- "unexpected-char-implies-table-voodoo":
- "Unexpected non-space characters in "
- "table context caused voodoo mode.",
+ "Unexpected implied end tag (%(name)s) in the table body phase.",
+ "unexpected-char-implies-table-voodoo": "Unexpected non-space characters in "
+ "table context caused voodoo mode.",
"unexpected-hidden-input-in-table":
- "Unexpected input with type hidden in table context.",
- "unexpected-form-in-table":
- "Unexpected form in table context.",
+ "Unexpected input with type hidden in table context.",
+ "unexpected-form-in-table": "Unexpected form in table context.",
"unexpected-start-tag-implies-table-voodoo":
- "Unexpected start tag (%(name)s) in "
- "table context caused voodoo mode.",
- "unexpected-end-tag-implies-table-voodoo":
- "Unexpected end tag (%(name)s) in "
- "table context caused voodoo mode.",
- "unexpected-cell-in-table-body":
- "Unexpected table cell start tag (%(name)s) "
- "in the table body phase.",
- "unexpected-cell-end-tag":
- "Got table cell end tag (%(name)s) "
- "while required end tags are missing.",
+ "Unexpected start tag (%(name)s) in "
+ "table context caused voodoo mode.",
+ "unexpected-end-tag-implies-table-voodoo": "Unexpected end tag (%(name)s) in "
+ "table context caused voodoo mode.",
+ "unexpected-cell-in-table-body": "Unexpected table cell start tag (%(name)s) "
+ "in the table body phase.",
+ "unexpected-cell-end-tag": "Got table cell end tag (%(name)s) "
+ "while required end tags are missing.",
"unexpected-end-tag-in-table-body":
- "Unexpected end tag (%(name)s) in the table body phase. Ignored.",
+ "Unexpected end tag (%(name)s) in the table body phase. Ignored.",
"unexpected-implied-end-tag-in-table-row":
- "Unexpected implied end tag (%(name)s) in the table row phase.",
+ "Unexpected implied end tag (%(name)s) in the table row phase.",
"unexpected-end-tag-in-table-row":
- "Unexpected end tag (%(name)s) in the table row phase. Ignored.",
+ "Unexpected end tag (%(name)s) in the table row phase. Ignored.",
"unexpected-select-in-select":
- "Unexpected select start tag in the select phase "
- "treated as select end tag.",
+ "Unexpected select start tag in the select phase "
+ "treated as select end tag.",
"unexpected-input-in-select":
- "Unexpected input start tag in the select phase.",
+ "Unexpected input start tag in the select phase.",
"unexpected-start-tag-in-select":
- "Unexpected start tag token (%(name)s in the select phase. "
- "Ignored.",
+ "Unexpected start tag token (%(name)s in the select phase. "
+ "Ignored.",
"unexpected-end-tag-in-select":
- "Unexpected end tag (%(name)s) in the select phase. Ignored.",
+ "Unexpected end tag (%(name)s) in the select phase. Ignored.",
"unexpected-table-element-start-tag-in-select-in-table":
- "Unexpected table element start tag (%(name)s) in the select in table phase.",
+ "Unexpected table element start tag (%(name)s) in the select in table phase.",
"unexpected-table-element-end-tag-in-select-in-table":
- "Unexpected table element end tag (%(name)s) in the select in table phase.",
+ "Unexpected table element end tag (%(name)s) in the select in table phase.",
"unexpected-char-after-body":
- "Unexpected non-space characters in the after body phase.",
- "unexpected-start-tag-after-body":
- "Unexpected start tag token (%(name)s)"
- " in the after body phase.",
- "unexpected-end-tag-after-body":
- "Unexpected end tag token (%(name)s)"
- " in the after body phase.",
+ "Unexpected non-space characters in the after body phase.",
+ "unexpected-start-tag-after-body": "Unexpected start tag token (%(name)s)"
+ " in the after body phase.",
+ "unexpected-end-tag-after-body": "Unexpected end tag token (%(name)s)"
+ " in the after body phase.",
"unexpected-char-in-frameset":
- "Unepxected characters in the frameset phase. Characters ignored.",
- "unexpected-start-tag-in-frameset":
- "Unexpected start tag token (%(name)s)"
- " in the frameset phase. Ignored.",
+ "Unepxected characters in the frameset phase. Characters ignored.",
+ "unexpected-start-tag-in-frameset": "Unexpected start tag token (%(name)s)"
+ " in the frameset phase. Ignored.",
"unexpected-frameset-in-frameset-innerhtml":
- "Unexpected end tag token (frameset) "
- "in the frameset phase (innerHTML).",
- "unexpected-end-tag-in-frameset":
- "Unexpected end tag token (%(name)s)"
- " in the frameset phase. Ignored.",
- "unexpected-char-after-frameset":
- "Unexpected non-space characters in the "
- "after frameset phase. Ignored.",
- "unexpected-start-tag-after-frameset":
- "Unexpected start tag (%(name)s)"
- " in the after frameset phase. Ignored.",
- "unexpected-end-tag-after-frameset":
- "Unexpected end tag (%(name)s)"
- " in the after frameset phase. Ignored.",
+ "Unexpected end tag token (frameset) "
+ "in the frameset phase (innerHTML).",
+ "unexpected-end-tag-in-frameset": "Unexpected end tag token (%(name)s)"
+ " in the frameset phase. Ignored.",
+ "unexpected-char-after-frameset": "Unexpected non-space characters in the "
+ "after frameset phase. Ignored.",
+ "unexpected-start-tag-after-frameset": "Unexpected start tag (%(name)s)"
+ " in the after frameset phase. Ignored.",
+ "unexpected-end-tag-after-frameset": "Unexpected end tag (%(name)s)"
+ " in the after frameset phase. Ignored.",
"unexpected-end-tag-after-body-innerhtml":
- "Unexpected end tag after body(innerHtml)",
+ "Unexpected end tag after body(innerHtml)",
"expected-eof-but-got-char":
- "Unexpected non-space characters. Expected end of file.",
- "expected-eof-but-got-start-tag":
- "Unexpected start tag (%(name)s)"
- ". Expected end of file.",
- "expected-eof-but-got-end-tag":
- "Unexpected end tag (%(name)s)"
- ". Expected end of file.",
- "eof-in-table":
- "Unexpected end of file. Expected table content.",
- "eof-in-select":
- "Unexpected end of file. Expected select content.",
- "eof-in-frameset":
- "Unexpected end of file. Expected frameset content.",
- "eof-in-script-in-script":
- "Unexpected end of file. Expected script content.",
- "eof-in-foreign-lands":
- "Unexpected end of file. Expected foreign content",
+ "Unexpected non-space characters. Expected end of file.",
+ "expected-eof-but-got-start-tag": "Unexpected start tag (%(name)s)"
+ ". Expected end of file.",
+ "expected-eof-but-got-end-tag": "Unexpected end tag (%(name)s)"
+ ". Expected end of file.",
+ "eof-in-table": "Unexpected end of file. Expected table content.",
+ "eof-in-select": "Unexpected end of file. Expected select content.",
+ "eof-in-frameset": "Unexpected end of file. Expected frameset content.",
+ "eof-in-script-in-script": "Unexpected end of file. Expected script content.",
+ "eof-in-foreign-lands": "Unexpected end of file. Expected foreign content",
"non-void-element-with-trailing-solidus":
- "Trailing solidus not allowed on element %(name)s",
+ "Trailing solidus not allowed on element %(name)s",
"unexpected-html-element-in-foreign-content":
- "Element %(name)s not allowed in a non-html context",
+ "Element %(name)s not allowed in a non-html context",
"unexpected-end-tag-before-html":
"Unexpected end tag (%(name)s) before html.",
- "undefined-error":
- "Undefined error (this sucks and should be fixed)",
+ "undefined-error": "Undefined error (this sucks and should be fixed)",
};
class Namespaces {
@@ -310,13 +246,20 @@
static String getPrefix(String url) {
switch (url) {
- case html: return 'html';
- case mathml: return 'math';
- case svg: return 'svg';
- case xlink: return 'xlink';
- case xml: return 'xml';
- case xmlns: return 'xmlns';
- default: return null;
+ case html:
+ return 'html';
+ case mathml:
+ return 'math';
+ case svg:
+ return 'svg';
+ case xlink:
+ return 'xlink';
+ case xml:
+ return 'xml';
+ case xmlns:
+ return 'xmlns';
+ default:
+ return null;
}
}
}
@@ -341,7 +284,6 @@
const Pair(Namespaces.svg, "title")
];
-
const formattingElements = const [
const Pair(Namespaces.html, "a"),
const Pair(Namespaces.html, "b"),
@@ -469,7 +411,7 @@
bool isWhitespaceCC(int charCode) {
switch (charCode) {
- case 9: // '\t'
+ case 9: // '\t'
case NEWLINE: // '\n'
case 12: // '\f'
case RETURN: // '\r'
@@ -514,10 +456,28 @@
bool isHexDigit(String char) {
if (char == null) return false;
switch (char.codeUnitAt(0)) {
- case 48: case 49: case 50: case 51: case 52: // '0' - '4'
- case 53: case 54: case 55: case 56: case 57: // '5' - '9'
- case 65: case 66: case 67: case 68: case 69: case 70: // 'A' - 'F'
- case 97: case 98: case 99: case 100: case 101: case 102: // 'a' - 'f'
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52: // '0' - '4'
+ case 53:
+ case 54:
+ case 55:
+ case 56:
+ case 57: // '5' - '9'
+ case 65:
+ case 66:
+ case 67:
+ case 68:
+ case 69:
+ case 70: // 'A' - 'F'
+ case 97:
+ case 98:
+ case 99:
+ case 100:
+ case 101:
+ case 102: // 'a' - 'f'
return true;
}
return false;
@@ -539,14 +499,7 @@
}
// Heading elements need to be ordered
-const headingElements = const [
- "h1",
- "h2",
- "h3",
- "h4",
- "h5",
- "h6"
-];
+const headingElements = const ["h1", "h2", "h3", "h4", "h5", "h6"];
const cdataElements = const ['title', 'textarea'];
@@ -564,8 +517,8 @@
"": const ["irrelevant",],
"style": const ["scoped",],
"img": const ["ismap",],
- "audio": const ["autoplay","controls"],
- "video": const ["autoplay","controls"],
+ "audio": const ["autoplay", "controls"],
+ "video": const ["autoplay", "controls"],
"script": const ["defer", "async"],
"details": const ["open",],
"datagrid": const ["multiple", "disabled"],
@@ -576,7 +529,14 @@
"option": const ["disabled", "readonly", "selected"],
"optgroup": const ["disabled", "readonly"],
"button": const ["disabled", "autofocus"],
- "input": const ["disabled", "readonly", "required", "autofocus", "checked", "ismap"],
+ "input": const [
+ "disabled",
+ "readonly",
+ "required",
+ "autofocus",
+ "checked",
+ "ismap"
+ ],
"select": const ["disabled", "readonly", "autofocus", "multiple"],
"output": const ["disabled", "readonly"],
};
@@ -584,38 +544,38 @@
// entitiesWindows1252 has to be _ordered_ and needs to have an index. It
// therefore can't be a frozenset.
const List<int> entitiesWindows1252 = const [
- 8364, // 0x80 0x20AC EURO SIGN
+ 8364, // 0x80 0x20AC EURO SIGN
65533, // 0x81 UNDEFINED
- 8218, // 0x82 0x201A SINGLE LOW-9 QUOTATION MARK
- 402, // 0x83 0x0192 LATIN SMALL LETTER F WITH HOOK
- 8222, // 0x84 0x201E DOUBLE LOW-9 QUOTATION MARK
- 8230, // 0x85 0x2026 HORIZONTAL ELLIPSIS
- 8224, // 0x86 0x2020 DAGGER
- 8225, // 0x87 0x2021 DOUBLE DAGGER
- 710, // 0x88 0x02C6 MODIFIER LETTER CIRCUMFLEX ACCENT
- 8240, // 0x89 0x2030 PER MILLE SIGN
- 352, // 0x8A 0x0160 LATIN CAPITAL LETTER S WITH CARON
- 8249, // 0x8B 0x2039 SINGLE LEFT-POINTING ANGLE QUOTATION MARK
- 338, // 0x8C 0x0152 LATIN CAPITAL LIGATURE OE
+ 8218, // 0x82 0x201A SINGLE LOW-9 QUOTATION MARK
+ 402, // 0x83 0x0192 LATIN SMALL LETTER F WITH HOOK
+ 8222, // 0x84 0x201E DOUBLE LOW-9 QUOTATION MARK
+ 8230, // 0x85 0x2026 HORIZONTAL ELLIPSIS
+ 8224, // 0x86 0x2020 DAGGER
+ 8225, // 0x87 0x2021 DOUBLE DAGGER
+ 710, // 0x88 0x02C6 MODIFIER LETTER CIRCUMFLEX ACCENT
+ 8240, // 0x89 0x2030 PER MILLE SIGN
+ 352, // 0x8A 0x0160 LATIN CAPITAL LETTER S WITH CARON
+ 8249, // 0x8B 0x2039 SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ 338, // 0x8C 0x0152 LATIN CAPITAL LIGATURE OE
65533, // 0x8D UNDEFINED
- 381, // 0x8E 0x017D LATIN CAPITAL LETTER Z WITH CARON
+ 381, // 0x8E 0x017D LATIN CAPITAL LETTER Z WITH CARON
65533, // 0x8F UNDEFINED
65533, // 0x90 UNDEFINED
- 8216, // 0x91 0x2018 LEFT SINGLE QUOTATION MARK
- 8217, // 0x92 0x2019 RIGHT SINGLE QUOTATION MARK
- 8220, // 0x93 0x201C LEFT DOUBLE QUOTATION MARK
- 8221, // 0x94 0x201D RIGHT DOUBLE QUOTATION MARK
- 8226, // 0x95 0x2022 BULLET
- 8211, // 0x96 0x2013 EN DASH
- 8212, // 0x97 0x2014 EM DASH
- 732, // 0x98 0x02DC SMALL TILDE
- 8482, // 0x99 0x2122 TRADE MARK SIGN
- 353, // 0x9A 0x0161 LATIN SMALL LETTER S WITH CARON
- 8250, // 0x9B 0x203A SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
- 339, // 0x9C 0x0153 LATIN SMALL LIGATURE OE
+ 8216, // 0x91 0x2018 LEFT SINGLE QUOTATION MARK
+ 8217, // 0x92 0x2019 RIGHT SINGLE QUOTATION MARK
+ 8220, // 0x93 0x201C LEFT DOUBLE QUOTATION MARK
+ 8221, // 0x94 0x201D RIGHT DOUBLE QUOTATION MARK
+ 8226, // 0x95 0x2022 BULLET
+ 8211, // 0x96 0x2013 EN DASH
+ 8212, // 0x97 0x2014 EM DASH
+ 732, // 0x98 0x02DC SMALL TILDE
+ 8482, // 0x99 0x2122 TRADE MARK SIGN
+ 353, // 0x9A 0x0161 LATIN SMALL LETTER S WITH CARON
+ 8250, // 0x9B 0x203A SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ 339, // 0x9C 0x0153 LATIN SMALL LIGATURE OE
65533, // 0x9D UNDEFINED
- 382, // 0x9E 0x017E LATIN SMALL LETTER Z WITH CARON
- 376 // 0x9F 0x0178 LATIN CAPITAL LETTER Y WITH DIAERESIS
+ 382, // 0x9E 0x017E LATIN SMALL LETTER Z WITH CARON
+ 376 // 0x9F 0x0178 LATIN CAPITAL LETTER Y WITH DIAERESIS
];
const xmlEntities = const ['lt;', 'gt;', 'amp;', 'apos;', 'quot;'];
diff --git a/lib/src/css_class_set.dart b/lib/src/css_class_set.dart
index 03136a7..8798cd2 100644
--- a/lib/src/css_class_set.dart
+++ b/lib/src/css_class_set.dart
@@ -9,7 +9,6 @@
import 'package:html5lib/dom.dart';
class ElementCssClassSet extends CssClassSetImpl {
-
final Element _element;
ElementCssClassSet(this._element);
@@ -28,12 +27,10 @@
}
void writeClasses(Set<String> s) {
- List list = new List.from(s);
_element.className = s.join(' ');
}
}
-
/** A Set that stores the CSS class names for an element. */
abstract class CssClassSet implements Set<String> {
@@ -112,7 +109,6 @@
}
abstract class CssClassSetImpl implements CssClassSet {
-
String toString() {
return readClasses().join(' ');
}
@@ -268,21 +264,19 @@
}
bool containsAll(Iterable<String> collection) =>
- readClasses().containsAll(collection);
+ readClasses().containsAll(collection);
Set<String> intersection(Set<String> other) =>
- readClasses().intersection(other);
+ readClasses().intersection(other);
- Set<String> union(Set<String> other) =>
- readClasses().union(other);
+ Set<String> union(Set<String> other) => readClasses().union(other);
- Set<String> difference(Set<String> other) =>
- readClasses().difference(other);
+ Set<String> difference(Set<String> other) => readClasses().difference(other);
String get first => readClasses().first;
String get last => readClasses().last;
String get single => readClasses().single;
- List<String> toList({ bool growable: true }) =>
+ List<String> toList({bool growable: true}) =>
readClasses().toList(growable: growable);
Set<String> toSet() => readClasses().toSet();
Iterable<String> take(int n) => readClasses().take(n);
@@ -291,9 +285,9 @@
Iterable<String> skip(int n) => readClasses().skip(n);
Iterable<String> skipWhile(bool test(String value)) =>
readClasses().skipWhile(test);
- dynamic firstWhere(bool test(String value), { Object orElse() }) =>
+ dynamic firstWhere(bool test(String value), {Object orElse()}) =>
readClasses().firstWhere(test, orElse: orElse);
- dynamic lastWhere(bool test(String value), { Object orElse()}) =>
+ dynamic lastWhere(bool test(String value), {Object orElse()}) =>
readClasses().lastWhere(test, orElse: orElse);
String singleWhere(bool test(String value)) =>
readClasses().singleWhere(test);
@@ -313,7 +307,7 @@
* After f returns, the modified set is written to the
* className property of this element.
*/
- modify( f(Set<String> s)) {
+ modify(f(Set<String> s)) {
Set<String> s = readClasses();
var ret = f(s);
writeClasses(s);
diff --git a/lib/src/encoding_parser.dart b/lib/src/encoding_parser.dart
index 8bb861c..04ffa0c 100644
--- a/lib/src/encoding_parser.dart
+++ b/lib/src/encoding_parser.dart
@@ -63,7 +63,7 @@
/// Skip past a list of characters. Defaults to skipping [isWhitespace].
String skipChars([CharPreciate skipChars]) {
if (skipChars == null) skipChars = isWhitespace;
- var p = position; // use property for the error-checking
+ var p = position; // use property for the error-checking
while (p < length) {
var c = _bytes[p];
if (!skipChars(c)) {
@@ -141,7 +141,8 @@
["</", handlePossibleEndTag],
["<!", handleOther],
["<?", handleOther],
- ["<", handlePossibleStartTag]];
+ ["<", handlePossibleStartTag]
+ ];
try {
for (var byte in data) {
@@ -324,7 +325,6 @@
}
}
-
class ContentAttrParser {
final EncodingBytes data;
@@ -370,7 +370,6 @@
}
}
-
bool isSpaceOrAngleBracket(String char) {
return char == ">" || char == "<" || isWhitespace(char);
}
diff --git a/lib/src/inputstream.dart b/lib/src/inputstream.dart
index 231fed0..fce5b21 100644
--- a/lib/src/inputstream.dart
+++ b/lib/src/inputstream.dart
@@ -69,9 +69,8 @@
///
/// [parseMeta] - Look for a <meta> element containing encoding information
HtmlInputStream(source, [String encoding, bool parseMeta = true,
- this.generateSpans = false, this.sourceUrl])
+ this.generateSpans = false, this.sourceUrl])
: charEncodingName = codecName(encoding) {
-
if (source is String) {
_rawChars = toCodepoints(source);
charEncodingName = 'utf-8';
@@ -140,7 +139,6 @@
fileInfo = new SourceFile.decoded(_chars, url: sourceUrl);
}
-
void detectEncoding([bool parseMeta = true]) {
// First look for a BOM
// This will also read past the BOM if present
@@ -259,7 +257,6 @@
}
}
-
// TODO(jmesserly): the Python code used a regex to check for this. But
// Dart doesn't let you create a regexp with invalid characters.
bool invalidUnicode(int c) {
@@ -269,15 +266,41 @@
if (0xD800 <= c && c <= 0xDFFF) return true;
if (0xFDD0 <= c && c <= 0xFDEF) return true;
switch (c) {
- case 0x000B: case 0xFFFE: case 0xFFFF: case 0x01FFFE: case 0x01FFFF:
- case 0x02FFFE: case 0x02FFFF: case 0x03FFFE: case 0x03FFFF:
- case 0x04FFFE: case 0x04FFFF: case 0x05FFFE: case 0x05FFFF:
- case 0x06FFFE: case 0x06FFFF: case 0x07FFFE: case 0x07FFFF:
- case 0x08FFFE: case 0x08FFFF: case 0x09FFFE: case 0x09FFFF:
- case 0x0AFFFE: case 0x0AFFFF: case 0x0BFFFE: case 0x0BFFFF:
- case 0x0CFFFE: case 0x0CFFFF: case 0x0DFFFE: case 0x0DFFFF:
- case 0x0EFFFE: case 0x0EFFFF: case 0x0FFFFE: case 0x0FFFFF:
- case 0x10FFFE: case 0x10FFFF:
+ case 0x000B:
+ case 0xFFFE:
+ case 0xFFFF:
+ case 0x01FFFE:
+ case 0x01FFFF:
+ case 0x02FFFE:
+ case 0x02FFFF:
+ case 0x03FFFE:
+ case 0x03FFFF:
+ case 0x04FFFE:
+ case 0x04FFFF:
+ case 0x05FFFE:
+ case 0x05FFFF:
+ case 0x06FFFE:
+ case 0x06FFFF:
+ case 0x07FFFE:
+ case 0x07FFFF:
+ case 0x08FFFE:
+ case 0x08FFFF:
+ case 0x09FFFE:
+ case 0x09FFFF:
+ case 0x0AFFFE:
+ case 0x0AFFFF:
+ case 0x0BFFFE:
+ case 0x0BFFFF:
+ case 0x0CFFFE:
+ case 0x0CFFFF:
+ case 0x0DFFFE:
+ case 0x0DFFFF:
+ case 0x0EFFFE:
+ case 0x0EFFFF:
+ case 0x0FFFFE:
+ case 0x0FFFFF:
+ case 0x10FFFE:
+ case 0x10FFFF:
return true;
}
return false;
diff --git a/lib/src/list_proxy.dart b/lib/src/list_proxy.dart
index 0ba7073..99acdb6 100644
--- a/lib/src/list_proxy.dart
+++ b/lib/src/list_proxy.dart
@@ -16,8 +16,7 @@
/// Creates a list proxy.
/// You can optionally specify the list to use for [storage] of the items,
/// otherwise this will create a [List<E>].
- ListProxy([List<E> storage])
- : _list = storage != null ? storage : <E>[];
+ ListProxy([List<E> storage]) : _list = storage != null ? storage : <E>[];
// TODO(jmesserly): This should be on List.
// See http://code.google.com/p/dart/issues/detail?id=947
@@ -43,18 +42,34 @@
// From List
E operator [](int index) => _list[index];
- operator []=(int index, E value) { _list[index] = value; }
- set length(int value) { _list.length = value; }
- void add(E value) { _list.add(value); }
+ operator []=(int index, E value) {
+ _list[index] = value;
+ }
+ set length(int value) {
+ _list.length = value;
+ }
+ void add(E value) {
+ _list.add(value);
+ }
- void addLast(E value) { add(value); }
- void addAll(Iterable<E> collection) { _list.addAll(collection); }
- void sort([int compare(E a, E b)]) { _list.sort(compare); }
- void shuffle([Random random]) { _list.shuffle(random); }
+ void addLast(E value) {
+ add(value);
+ }
+ void addAll(Iterable<E> collection) {
+ _list.addAll(collection);
+ }
+ void sort([int compare(E a, E b)]) {
+ _list.sort(compare);
+ }
+ void shuffle([Random random]) {
+ _list.shuffle(random);
+ }
int indexOf(E element, [int start = 0]) => _list.indexOf(element, start);
int lastIndexOf(E element, [int start]) => _list.lastIndexOf(element, start);
- void clear() { _list.clear(); }
+ void clear() {
+ _list.clear();
+ }
E removeAt(int index) => _list.removeAt(index);
E removeLast() => _list.removeLast();
@@ -69,7 +84,9 @@
void setRange(int start, int length, List<E> from, [int startFrom = 0]) {
_list.setRange(start, length, from, startFrom);
}
- void removeRange(int start, int length) { _list.removeRange(start, length); }
+ void removeRange(int start, int length) {
+ _list.removeRange(start, length);
+ }
void insertAll(int index, Iterable<E> iterable) {
_list.insertAll(index, iterable);
}
@@ -83,6 +100,6 @@
void setAll(int index, Iterable<E> iterable) => _list.setAll(index, iterable);
- void fillRange(int start, int end, [E fillValue])
- => _list.fillRange(start, end, fillValue);
+ void fillRange(int start, int end, [E fillValue]) =>
+ _list.fillRange(start, end, fillValue);
}
diff --git a/lib/src/query_selector.dart b/lib/src/query_selector.dart
index ededa54..556eeb0 100644
--- a/lib/src/query_selector.dart
+++ b/lib/src/query_selector.dart
@@ -15,8 +15,8 @@
List<Element> querySelectorAll(Node node, String selector) {
var results = [];
- new SelectorEvaluator()
- .querySelectorAll(node, _parseSelectorList(selector), results);
+ new SelectorEvaluator().querySelectorAll(
+ node, _parseSelectorList(selector), results);
return results;
}
@@ -49,9 +49,8 @@
return null;
}
- void querySelectorAll(Node root, SelectorGroup selector,
- List<Element> results) {
-
+ void querySelectorAll(
+ Node root, SelectorGroup selector, List<Element> results) {
for (var node in root.nodes) {
if (node is! Element) continue;
if (matches(node, selector)) results.add(node);
@@ -59,7 +58,6 @@
}
}
-
bool visitSelectorGroup(SelectorGroup group) =>
group.selectors.any(visitSelector);
@@ -109,8 +107,10 @@
// For now, just remember what the combinator was.
combinator = s.combinator;
break;
- case TokenKind.COMBINATOR_NONE: break;
- default: throw _unsupported(selector);
+ case TokenKind.COMBINATOR_NONE:
+ break;
+ default:
+ throw _unsupported(selector);
}
if (_element == null) {
@@ -123,9 +123,9 @@
return result;
}
- _unimplemented(SimpleSelector selector) =>
- new UnimplementedError("'$selector' selector of type "
- "${selector.runtimeType} is not implemented");
+ _unimplemented(SimpleSelector selector) => new UnimplementedError(
+ "'$selector' selector of type "
+ "${selector.runtimeType} is not implemented");
_unsupported(selector) =>
new FormatException("'$selector' is not a valid selector");
@@ -142,8 +142,8 @@
// http://dev.w3.org/csswg/selectors-4/#the-empty-pseudo
case 'empty':
- return _element.nodes.any((n) => !(n is Element ||
- n is Text && n.text.isNotEmpty));
+ return _element.nodes
+ .any((n) => !(n is Element || n is Text && n.text.isNotEmpty));
// http://dev.w3.org/csswg/selectors-4/#the-blank-pseudo
case 'blank':
@@ -179,7 +179,6 @@
throw _unimplemented(selector);
}
-
bool visitPseudoElementSelector(PseudoElementSelector selector) {
// :before, :after, :first-letter/line can't match DOM elements.
if (_isLegacyPsuedoClass(selector.name)) return false;
@@ -189,9 +188,13 @@
static bool _isLegacyPsuedoClass(String name) {
switch (name) {
- case 'before': case 'after': case 'first-line': case 'first-letter':
+ case 'before':
+ case 'after':
+ case 'first-line':
+ case 'first-letter':
return true;
- default: return false;
+ default:
+ return false;
}
}
@@ -209,7 +212,8 @@
if (exprs.length == 1 && exprs[0] is LiteralTerm) {
LiteralTerm literal = exprs[0];
var parent = _element.parentNode;
- return parent != null && literal.value > 0 &&
+ return parent != null &&
+ literal.value > 0 &&
parent.nodes.indexOf(_element) == literal.value;
}
break;
@@ -282,7 +286,8 @@
return value.endsWith(select);
case TokenKind.SUBSTRING_MATCH:
return value.contains(select);
- default: throw _unsupported(selector);
+ default:
+ throw _unsupported(selector);
}
}
}
diff --git a/lib/src/token.dart b/lib/src/token.dart
index 9340153..e4f25e5 100644
--- a/lib/src/token.dart
+++ b/lib/src/token.dart
@@ -106,7 +106,6 @@
TagAttribute(this.name, [this.value = '']);
}
-
class TokenKind {
static const int spaceCharacters = 0;
static const int characters = 1;
diff --git a/lib/src/tokenizer.dart b/lib/src/tokenizer.dart
index 1b63114..a7ebcf8 100644
--- a/lib/src/tokenizer.dart
+++ b/lib/src/tokenizer.dart
@@ -69,7 +69,7 @@
this.lowercaseElementName: true, this.lowercaseAttrName: true,
bool generateSpans: false, String sourceUrl, this.attributeSpans: false})
: stream = new HtmlInputStream(
- doc, encoding, parseMeta, generateSpans, sourceUrl),
+ doc, encoding, parseMeta, generateSpans, sourceUrl),
tokenQueue = new Queue(),
generateSpans = generateSpans {
reset();
@@ -134,7 +134,7 @@
if (stream.errors.length > 0) {
_current = new ParseErrorToken(stream.errors.removeFirst());
} else {
- assert (tokenQueue.length > 0);
+ assert(tokenQueue.length > 0);
_current = tokenQueue.removeFirst();
}
return true;
@@ -191,14 +191,12 @@
// Certain characters get replaced with others
var char = replacementCharacters[charAsInt];
if (char != null) {
- _addToken(new ParseErrorToken(
- "illegal-codepoint-for-numeric-entity",
+ _addToken(new ParseErrorToken("illegal-codepoint-for-numeric-entity",
messageParams: {"charAsInt": charAsInt}));
- } else if ((0xD800 <= charAsInt && charAsInt <= 0xDFFF)
- || (charAsInt > 0x10FFFF)) {
+ } else if ((0xD800 <= charAsInt && charAsInt <= 0xDFFF) ||
+ (charAsInt > 0x10FFFF)) {
char = "\uFFFD";
- _addToken(new ParseErrorToken(
- "illegal-codepoint-for-numeric-entity",
+ _addToken(new ParseErrorToken("illegal-codepoint-for-numeric-entity",
messageParams: {"charAsInt": charAsInt}));
} else {
// Should speed up this check somehow (e.g. move the set to a constant)
@@ -206,17 +204,44 @@
(0x000E <= charAsInt && charAsInt <= 0x001F) ||
(0x007F <= charAsInt && charAsInt <= 0x009F) ||
(0xFDD0 <= charAsInt && charAsInt <= 0xFDEF) ||
- const [0x000B, 0xFFFE, 0xFFFF, 0x1FFFE,
- 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE,
- 0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE,
- 0x5FFFF, 0x6FFFE, 0x6FFFF, 0x7FFFE,
- 0x7FFFF, 0x8FFFE, 0x8FFFF, 0x9FFFE,
- 0x9FFFF, 0xAFFFE, 0xAFFFF, 0xBFFFE,
- 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE,
- 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE,
- 0xFFFFF, 0x10FFFE, 0x10FFFF].contains(charAsInt)) {
- _addToken(new ParseErrorToken(
- "illegal-codepoint-for-numeric-entity",
+ const [
+ 0x000B,
+ 0xFFFE,
+ 0xFFFF,
+ 0x1FFFE,
+ 0x1FFFF,
+ 0x2FFFE,
+ 0x2FFFF,
+ 0x3FFFE,
+ 0x3FFFF,
+ 0x4FFFE,
+ 0x4FFFF,
+ 0x5FFFE,
+ 0x5FFFF,
+ 0x6FFFE,
+ 0x6FFFF,
+ 0x7FFFE,
+ 0x7FFFF,
+ 0x8FFFE,
+ 0x8FFFF,
+ 0x9FFFE,
+ 0x9FFFF,
+ 0xAFFFE,
+ 0xAFFFF,
+ 0xBFFFE,
+ 0xBFFFF,
+ 0xCFFFE,
+ 0xCFFFF,
+ 0xDFFFE,
+ 0xDFFFF,
+ 0xEFFFE,
+ 0xEFFFF,
+ 0xFFFFE,
+ 0xFFFFF,
+ 0x10FFFE,
+ 0x10FFFF
+ ].contains(charAsInt)) {
+ _addToken(new ParseErrorToken("illegal-codepoint-for-numeric-entity",
messageParams: {"charAsInt": charAsInt}));
}
char = new String.fromCharCodes([charAsInt]);
@@ -225,8 +250,7 @@
// Discard the ; if present. Otherwise, put it back on the queue and
// invoke parseError on parser.
if (c != ";") {
- _addToken(new ParseErrorToken(
- "numeric-entity-without-semicolon"));
+ _addToken(new ParseErrorToken("numeric-entity-without-semicolon"));
stream.unget(c);
}
return char;
@@ -237,8 +261,11 @@
var output = "&";
var charStack = [stream.char()];
- if (isWhitespace(charStack[0]) || charStack[0] == '<' || charStack[0] == '&'
- || charStack[0] == EOF || allowedChar == charStack[0]) {
+ if (isWhitespace(charStack[0]) ||
+ charStack[0] == '<' ||
+ charStack[0] == '&' ||
+ charStack[0] == EOF ||
+ allowedChar == charStack[0]) {
stream.unget(charStack[0]);
} else if (charStack[0] == "#") {
// Read the next character to see if it's hex or decimal
@@ -272,8 +299,8 @@
while (charStack.last != EOF) {
var name = charStack.join();
- filteredEntityList = filteredEntityList.where(
- (e) => e.startsWith(name)).toList();
+ filteredEntityList =
+ filteredEntityList.where((e) => e.startsWith(name)).toList();
if (filteredEntityList.length == 0) {
break;
@@ -300,12 +327,12 @@
if (entityName != null) {
var lastChar = entityName[entityName.length - 1];
if (lastChar != ";") {
- _addToken(new ParseErrorToken(
- "named-entity-without-semicolon"));
+ _addToken(new ParseErrorToken("named-entity-without-semicolon"));
}
- if (lastChar != ";" && fromAttribute &&
+ if (lastChar != ";" &&
+ fromAttribute &&
(isLetterOrDigit(charStack[entityLen]) ||
- charStack[entityLen] == '=')) {
+ charStack[entityLen] == '=')) {
stream.unget(charStack.removeLast());
output = "&${charStack.join()}";
} else {
@@ -482,8 +509,7 @@
_addToken(new ParseErrorToken("invalid-codepoint"));
_addToken(new CharactersToken("\uFFFD"));
} else {
- _addToken(new CharactersToken(
- '${data}${stream.charsUntil("\u0000")}'));
+ _addToken(new CharactersToken('${data}${stream.charsUntil("\u0000")}'));
}
return true;
}
@@ -500,15 +526,13 @@
} else if (data == ">") {
// XXX In theory it could be something besides a tag name. But
// do we really care?
- _addToken(new ParseErrorToken(
- "expected-tag-name-but-got-right-bracket"));
+ _addToken(new ParseErrorToken("expected-tag-name-but-got-right-bracket"));
_addToken(new CharactersToken("<>"));
state = dataState;
} else if (data == "?") {
// XXX In theory it could be something besides a tag name. But
// do we really care?
- _addToken(new ParseErrorToken(
- "expected-tag-name-but-got-question-mark"));
+ _addToken(new ParseErrorToken("expected-tag-name-but-got-question-mark"));
stream.unget(data);
state = bogusCommentState;
} else {
@@ -527,18 +551,17 @@
currentToken = new EndTagToken(data);
state = tagNameState;
} else if (data == ">") {
- _addToken(new ParseErrorToken(
- "expected-closing-tag-but-got-right-bracket"));
+ _addToken(
+ new ParseErrorToken("expected-closing-tag-but-got-right-bracket"));
state = dataState;
} else if (data == EOF) {
- _addToken(new ParseErrorToken(
- "expected-closing-tag-but-got-eof"));
+ _addToken(new ParseErrorToken("expected-closing-tag-but-got-eof"));
_addToken(new CharactersToken("</"));
state = dataState;
} else {
// XXX data can be _'_...
- _addToken(new ParseErrorToken(
- "expected-closing-tag-but-got-char", messageParams: {"data": data}));
+ _addToken(new ParseErrorToken("expected-closing-tag-but-got-char",
+ messageParams: {"data": data}));
stream.unget(data);
state = bogusCommentState;
}
@@ -1219,8 +1242,8 @@
stream.unget(data);
state = dataState;
} else {
- _addToken(new ParseErrorToken(
- "unexpected-character-after-attribute-value"));
+ _addToken(
+ new ParseErrorToken("unexpected-character-after-attribute-value"));
stream.unget(data);
state = beforeAttributeNameState;
}
@@ -1237,8 +1260,8 @@
stream.unget(data);
state = dataState;
} else {
- _addToken(new ParseErrorToken(
- "unexpected-character-after-soldius-in-tag"));
+ _addToken(
+ new ParseErrorToken("unexpected-character-after-soldius-in-tag"));
stream.unget(data);
state = beforeAttributeNameState;
}
@@ -1285,9 +1308,10 @@
return true;
}
} else if (charStack.last == "[" &&
- parser != null && parser.tree.openElements.length > 0 &&
- parser.tree.openElements.last.namespaceUri
- != parser.tree.defaultNamespace) {
+ parser != null &&
+ parser.tree.openElements.length > 0 &&
+ parser.tree.openElements.last.namespaceUri !=
+ parser.tree.defaultNamespace) {
var matched = true;
for (var expected in const ["C", "D", "A", "T", "A", "["]) {
charStack.add(stream.char());
@@ -1402,12 +1426,12 @@
currentStringToken.data = '${currentStringToken.data}--\uFFFD';
state = commentState;
} else if (data == "!") {
- _addToken(new ParseErrorToken(
- "unexpected-bang-after-double-dash-in-comment"));
+ _addToken(
+ new ParseErrorToken("unexpected-bang-after-double-dash-in-comment"));
state = commentEndBangState;
} else if (data == "-") {
- _addToken(new ParseErrorToken(
- "unexpected-dash-after-double-dash-in-comment"));
+ _addToken(
+ new ParseErrorToken("unexpected-dash-after-double-dash-in-comment"));
currentStringToken.data = '${currentStringToken.data}$data';
} else if (data == EOF) {
_addToken(new ParseErrorToken("eof-in-comment-double-dash"));
@@ -1450,8 +1474,7 @@
if (isWhitespace(data)) {
state = beforeDoctypeNameState;
} else if (data == EOF) {
- _addToken(new ParseErrorToken(
- "expected-doctype-name-but-got-eof"));
+ _addToken(new ParseErrorToken("expected-doctype-name-but-got-eof"));
currentDoctypeToken.correct = false;
_addToken(currentToken);
state = dataState;
@@ -1468,8 +1491,8 @@
if (isWhitespace(data)) {
return true;
} else if (data == ">") {
- _addToken(new ParseErrorToken(
- "expected-doctype-name-but-got-right-bracket"));
+ _addToken(
+ new ParseErrorToken("expected-doctype-name-but-got-right-bracket"));
currentDoctypeToken.correct = false;
_addToken(currentToken);
state = dataState;
@@ -1478,8 +1501,7 @@
currentDoctypeToken.name = "\uFFFD";
state = doctypeNameState;
} else if (data == EOF) {
- _addToken(new ParseErrorToken(
- "expected-doctype-name-but-got-eof"));
+ _addToken(new ParseErrorToken("expected-doctype-name-but-got-eof"));
currentDoctypeToken.correct = false;
_addToken(currentToken);
state = dataState;
@@ -1883,4 +1905,3 @@
return true;
}
}
-
diff --git a/lib/src/treebuilder.dart b/lib/src/treebuilder.dart
index 4b8dfc4..edd183d 100644
--- a/lib/src/treebuilder.dart
+++ b/lib/src/treebuilder.dart
@@ -61,7 +61,6 @@
return true;
}
-
bool _nodesEqual(Element node1, Element node2) {
return getElementNameTuple(node1) == getElementNameTuple(node2) &&
_mapEquals(node1.attributes, node2.attributes);
@@ -117,16 +116,22 @@
listElements2 = const [const Pair(Namespaces.html, "button")];
break;
case "list":
- listElements2 = const [const Pair(Namespaces.html, "ol"),
- const Pair(Namespaces.html, "ul")];
+ listElements2 = const [
+ const Pair(Namespaces.html, "ol"),
+ const Pair(Namespaces.html, "ul")
+ ];
break;
case "table":
- listElements1 = const [const Pair(Namespaces.html, "html"),
- const Pair(Namespaces.html, "table")];
+ listElements1 = const [
+ const Pair(Namespaces.html, "html"),
+ const Pair(Namespaces.html, "table")
+ ];
break;
case "select":
- listElements1 = const [const Pair(Namespaces.html, "optgroup"),
- const Pair(Namespaces.html, "option")];
+ listElements1 = const [
+ const Pair(Namespaces.html, "optgroup"),
+ const Pair(Namespaces.html, "option")
+ ];
invert = true;
break;
default:
@@ -140,7 +145,7 @@
return true;
} else if (invert !=
(listElements1.contains(getElementNameTuple(node)) ||
- listElements2.contains(getElementNameTuple(node)))) {
+ listElements2.contains(getElementNameTuple(node)))) {
return false;
}
}
@@ -185,11 +190,10 @@
entry = activeFormattingElements[i];
// TODO(jmesserly): optimize this. No need to create a token.
- var cloneToken = new StartTagToken(
- entry.localName,
+ var cloneToken = new StartTagToken(entry.localName,
namespace: entry.namespaceUri,
data: new LinkedHashMap.from(entry.attributes))
- ..span = entry.sourceSpan;
+ ..span = entry.sourceSpan;
// Step 9
var element = insertElement(cloneToken);
@@ -235,7 +239,7 @@
void insertDoctype(DoctypeToken token) {
var doctype = new DocumentType(token.name, token.publicId, token.systemId)
- ..sourceSpan = token.span;
+ ..sourceSpan = token.span;
document.nodes.add(doctype);
}
@@ -252,8 +256,8 @@
var namespace = token.namespace;
if (namespace == null) namespace = defaultNamespace;
var element = document.createElementNS(namespace, name)
- ..attributes = token.data
- ..sourceSpan = token.span;
+ ..attributes = token.data
+ ..sourceSpan = token.span;
return element;
}
@@ -267,8 +271,8 @@
var namespace = token.namespace;
if (namespace == null) namespace = defaultNamespace;
var element = document.createElementNS(namespace, name)
- ..attributes = token.data
- ..sourceSpan = token.span;
+ ..attributes = token.data
+ ..sourceSpan = token.span;
openElements.last.nodes.add(element);
openElements.add(element);
return element;
@@ -300,8 +304,9 @@
void insertText(String data, FileSpan span) {
var parent = openElements.last;
- if (!insertFromTable || insertFromTable &&
- !tableInsertModeElements.contains(openElements.last.localName)) {
+ if (!insertFromTable ||
+ insertFromTable &&
+ !tableInsertModeElements.contains(openElements.last.localName)) {
_insertText(parent, data, span);
} else {
// We should be in the InTable mode. This means we want to do
@@ -322,8 +327,8 @@
last.data = '${last.data}$data';
if (span != null) {
- last.sourceSpan = span.file.span(last.sourceSpan.start.offset,
- span.end.offset);
+ last.sourceSpan =
+ span.file.span(last.sourceSpan.start.offset, span.end.offset);
}
} else {
nodes.add(new Text(data)..sourceSpan = span);
@@ -372,8 +377,17 @@
void generateImpliedEndTags([String exclude]) {
var name = openElements.last.localName;
// XXX td, th and tr are not actually needed
- if (name != exclude && const ["dd", "dt", "li", "option", "optgroup", "p",
- "rp", "rt"].contains(name)) {
+ if (name != exclude &&
+ const [
+ "dd",
+ "dt",
+ "li",
+ "option",
+ "optgroup",
+ "p",
+ "rp",
+ "rt"
+ ].contains(name)) {
openElements.removeLast();
// XXX This is not entirely what the specification says. We should
// investigate it more closely.
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index c998e0f..fb58cf1 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -79,7 +79,8 @@
data.forEach((key, value) {
var result = new StringBuffer();
var search = '%($key)';
- int last = 0, match;
+ int last = 0,
+ match;
while ((match = format.indexOf(search, last)) >= 0) {
result.write(format.substring(last, match));
match += search.length;
@@ -106,8 +107,9 @@
var number = value.toRadixString(16);
result.write(padWithZeros(number, numberSize));
break;
- default: throw "not implemented: formatStr does not support format "
- "character ${format[match]}";
+ default:
+ throw "not implemented: formatStr does not support format "
+ "character ${format[match]}";
}
last = match + 1;
diff --git a/pubspec.yaml b/pubspec.yaml
index 2be7677..87d6fc7 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,8 +1,8 @@
name: html5lib
-version: 0.12.0
+version: 0.12.1-dev
author: Dart Team <misc@dartlang.org>
description: A library for working with HTML documents.
-homepage: http://pub.dartlang.org/packages/html5lib
+homepage: https://github.com/dart-lang/html5lib
environment:
sdk: '>=1.2.0 <2.0.0'
dependencies:
@@ -11,4 +11,4 @@
utf: '>=0.9.0 <0.10.0'
dev_dependencies:
path: '>=0.9.0 <2.0.0'
- unittest: '>=0.10.0 <0.11.0'
+ unittest: '>=0.10.0 <0.12.0'
diff --git a/test/dom_test.dart b/test/dom_test.dart
index 9251faf..14b095b 100644
--- a/test/dom_test.dart
+++ b/test/dom_test.dart
@@ -6,7 +6,6 @@
import 'package:html5lib/parser.dart';
main() {
-
group('Element', () {
test('classes', () {
final barBaz = new Element.html('<div class=" bar baz"></div>');
@@ -20,9 +19,9 @@
group('Document', () {
final doc = parse('<div id=foo>'
- '<div class=" bar baz"></div>'
- '<div class="qux baz "></div>'
- '<div id=Foo>');
+ '<div class=" bar baz"></div>'
+ '<div class="qux baz "></div>'
+ '<div id=Foo>');
test('getElementById', () {
var foo = doc.body.nodes[0];
diff --git a/test/parser_feature_test.dart b/test/parser_feature_test.dart
index 2950a77..ddc8a74 100644
--- a/test/parser_feature_test.dart
+++ b/test/parser_feature_test.dart
@@ -129,8 +129,8 @@
var doc = parse(text, generateSpans: true);
var elem = doc.querySelector('foo');
- expect(elem.attributeSpans['template'].start.offset,
- text.indexOf('template'));
+ expect(
+ elem.attributeSpans['template'].start.offset, text.indexOf('template'));
expect(elem.attributeValueSpans.containsKey('template'), false);
});
@@ -246,7 +246,7 @@
'Unexpected non-space characters. Expected DOCTYPE.');
expect(parser.errors[0].toString(),
'ParserError on line 1, column 4: Unexpected non-space characters. '
- 'Expected DOCTYPE.\n'
+ 'Expected DOCTYPE.\n'
'foo\n'
' ^');
});
diff --git a/test/parser_test.dart b/test/parser_test.dart
index 821eb2d..ed11982 100644
--- a/test/parser_test.dart
+++ b/test/parser_test.dart
@@ -20,7 +20,7 @@
// final namespaceExpected = new RegExp(@"^(\s*)<(\S+)>", multiLine: true);
// return expected.replaceAll(namespaceExpected, @"$1<html $2>");
final namespaceExpected = new RegExp(r"^(\|\s*)<(\S+)>");
- var lines = expected.split("\n");
+ var lines = expected.split("\n");
for (int i = 0; i < lines.length; i++) {
var match = namespaceExpected.firstMatch(lines[i]);
if (match != null) {
@@ -52,21 +52,19 @@
expected = namespaceHtml(expected);
}
- expect(output, equals(expected), reason:
- "\n\nInput:\n$input\n\nExpected:\n$expected\n\nReceived:\n$output");
+ expect(output, equals(expected),
+ reason: "\n\nInput:\n$input\n\nExpected:\n$expected\n\nReceived:\n$output");
if (checkParseErrors) {
- expect(parser.errors.length, equals(errors.length), reason:
- "\n\nInput:\n$input\n\nExpected errors (${errors.length}):\n"
+ expect(parser.errors.length, equals(errors.length),
+ reason: "\n\nInput:\n$input\n\nExpected errors (${errors.length}):\n"
"${errors.join('\n')}\n\n"
"Actual errors (${parser.errors.length}):\n"
"${parser.errors.map((e) => '$e').join('\n')}");
}
}
-
void main() {
-
test('dart:io', () {
// ensure IO support is unregistered
expect(inputstream.consoleSupport,
@@ -84,7 +82,6 @@
var testName = pathos.basenameWithoutExtension(path);
group(testName, () {
- int index = 0;
for (var testData in tests) {
var input = testData['data'];
var errors = testData['errors'];
@@ -102,8 +99,6 @@
});
}
}
-
- index++;
}
});
}
@@ -116,6 +111,6 @@
.replaceAll(new RegExp('\\\\.'), '_')
.replaceAll(new RegExp('\u0000'), '_')
.replaceAll('"', '\\"')
- .replaceAll(new RegExp('[\n\r\t]'),'_');
+ .replaceAll(new RegExp('[\n\r\t]'), '_');
return JSON.decode('"$escapeQuote"');
}
diff --git a/test/run.sh b/test/run.sh
index f269bda..c060bd7 100755
--- a/test/run.sh
+++ b/test/run.sh
@@ -15,8 +15,8 @@
# TODO(jmesserly): switch to new analyzer. Note: it's missing a lot of the
# tests for implemented members; we should get that fixed before switching.
echo Analyzing library for warnings or type errors
-dartanalyzer --fatal-warnings --fatal-type-errors lib/*.dart || \
+dartanalyzer --fatal-warnings lib/*.dart || \
echo "ignore analyzer errors"
popd
-dart --enable-type-checks --enable-asserts test/run_all.dart $@
+dart --checked test/run_all.dart $@
diff --git a/test/selectors/level1_baseline_test.dart b/test/selectors/level1_baseline_test.dart
index cf9373c..2a2f2f0 100644
--- a/test/selectors/level1_baseline_test.dart
+++ b/test/selectors/level1_baseline_test.dart
@@ -18,7 +18,7 @@
}
var testType = TEST_QSA_BASELINE; // Only run baseline tests.
-var docType = "html"; // Only run tests suitable for HTML
+var docType = "html"; // Only run tests suitable for HTML
main() {
/*
@@ -59,21 +59,24 @@
//doc = frame.contentDocument; // Document Node tests
doc = getTestContentDocument();
- var element = doc.getElementById("root"); // In-document Element Node tests
+ var element = doc.getElementById("root"); // In-document Element Node tests
//Setup the namespace tests
setupSpecialElements(element);
- var outOfScope = element.clone(true); // Append this to the body before running the in-document
- // Element tests, but after running the Document tests. This
- // tests that no elements that are not descendants of element
- // are selected.
+ var outOfScope = element
+ .clone(true); // Append this to the body before running the in-document
+ // Element tests, but after running the Document tests. This
+ // tests that no elements that are not descendants of element
+ // are selected.
- traverse(outOfScope, (elem) { // Annotate each element as being a clone; used for verifying
- elem.attributes["data-clone"] = ""; // that none of these elements ever match.
+ traverse(outOfScope, (elem) {
+ // Annotate each element as being a clone; used for verifying
+ elem.attributes["data-clone"] =
+ ""; // that none of these elements ever match.
});
- var detached = element.clone(true); // Detached Element Node tests
+ var detached = element.clone(true); // Detached Element Node tests
var fragment = doc.createDocumentFragment(); // Fragment Node tests
fragment.append(element.clone(true));
@@ -101,17 +104,19 @@
//runInvalidSelectorTest("In-document Element", element, invalidSelectors);
runValidSelectorTest("Document", doc, validSelectors, testType, docType);
- runValidSelectorTest("Detached Element", detached, validSelectors, testType, docType);
+ runValidSelectorTest(
+ "Detached Element", detached, validSelectors, testType, docType);
runValidSelectorTest("Fragment", fragment, validSelectors, testType, docType);
group('out of scope', () {
setUp(() {
doc.body.append(outOfScope); // Append before in-document Element tests.
- // None of these elements should match
+ // None of these elements should match
});
tearDown(() {
outOfScope.remove();
});
- runValidSelectorTest("In-document Element", element, validSelectors, testType, docType);
+ runValidSelectorTest(
+ "In-document Element", element, validSelectors, testType, docType);
});
}
diff --git a/test/selectors/level1_lib.dart b/test/selectors/level1_lib.dart
index 31e0faf..30ef1a1 100644
--- a/test/selectors/level1_lib.dart
+++ b/test/selectors/level1_lib.dart
@@ -29,28 +29,34 @@
noNS.id = "no-namespace";
var div;
- div = [doc.createElement("div"),
- doc.createElementNS("http://www.w3.org/1999/xhtml", "div"),
- doc.createElementNS("", "div"),
- doc.createElementNS("http://www.example.org/ns", "div")];
+ div = [
+ doc.createElement("div"),
+ doc.createElementNS("http://www.w3.org/1999/xhtml", "div"),
+ doc.createElementNS("", "div"),
+ doc.createElementNS("http://www.example.org/ns", "div")
+ ];
div[0].id = "any-namespace-div1";
div[1].id = "any-namespace-div2";
- div[2].attributes["id"] = "any-namespace-div3"; // Non-HTML elements can't use .id property
+ div[2].attributes["id"] =
+ "any-namespace-div3"; // Non-HTML elements can't use .id property
div[3].attributes["id"] = "any-namespace-div4";
for (var i = 0; i < div.length; i++) {
anyNS.append(div[i]);
}
- div = [doc.createElement("div"),
- doc.createElementNS("http://www.w3.org/1999/xhtml", "div"),
- doc.createElementNS("", "div"),
- doc.createElementNS("http://www.example.org/ns", "div")];
+ div = [
+ doc.createElement("div"),
+ doc.createElementNS("http://www.w3.org/1999/xhtml", "div"),
+ doc.createElementNS("", "div"),
+ doc.createElementNS("http://www.example.org/ns", "div")
+ ];
div[0].id = "no-namespace-div1";
div[1].id = "no-namespace-div2";
- div[2].attributes["id"] = "no-namespace-div3"; // Non-HTML elements can't use .id property
+ div[2].attributes["id"] =
+ "no-namespace-div3"; // Non-HTML elements can't use .id property
div[3].attributes["id"] = "no-namespace-div4";
for (var i = 0; i < div.length; i++) {
@@ -72,14 +78,15 @@
test(() {
var qa = obj.querySelectorAll is Function;
- assert_true( qa, type + " supports querySelectorAll.");
+ assert_true(qa, type + " supports querySelectorAll.");
}, type + " supports querySelectorAll");
test(() {
var list = obj.querySelectorAll("div");
// TODO(jmesserly): testing List<Element> for now. It should return an
// ElementList which has extra properties. Needed for dart:html compat.
- assert_true(list is List<Element>, "The result should be an instance of a NodeList");
+ assert_true(list is List<Element>,
+ "The result should be an instance of a NodeList");
}, type + ".querySelectorAll returns NodeList instance");
}
@@ -97,12 +104,14 @@
var div = doc.createElement("div");
(root is Document ? root.body : root).append(div);
- assert_equals(pre.length, preLength, "The length of the NodeList should not change.");
+ assert_equals(
+ pre.length, preLength, "The length of the NodeList should not change.");
}, type + ": static NodeList");
test(() {
post = root.querySelectorAll("div");
- assert_equals(post.length, preLength + 1, "The length of the new NodeList should be 1 more than the previous list.");
+ assert_equals(post.length, preLength + 1,
+ "The length of the new NodeList should be 1 more than the previous list.");
}, type + ": new NodeList");
}
@@ -113,46 +122,58 @@
runSpecialSelectorTests(type, root) {
// Dart note: changed these tests because we don't have auto conversion to
// String like JavaScript does.
- test(() { // 1
- assert_equals(root.querySelectorAll('null').length, 1, "This should find one element with the tag name 'NULL'.");
+ test(() {
+ // 1
+ assert_equals(root.querySelectorAll('null').length, 1,
+ "This should find one element with the tag name 'NULL'.");
}, type + ".querySelectorAll null");
- test(() { // 2
- assert_equals(root.querySelectorAll('undefined').length, 1, "This should find one element with the tag name 'UNDEFINED'.");
+ test(() {
+ // 2
+ assert_equals(root.querySelectorAll('undefined').length, 1,
+ "This should find one element with the tag name 'UNDEFINED'.");
}, type + ".querySelectorAll undefined");
- test(() { // 3
+ test(() {
+ // 3
assert_throws((e) => e is NoSuchMethodError, () {
root.querySelectorAll();
}, "This should throw a TypeError.");
}, type + ".querySelectorAll no parameter");
- test(() { // 4
+ test(() {
+ // 4
var elm = root.querySelector('null');
assert_not_equals(elm, null, "This should find an element.");
// TODO(jmesserly): change "localName" back to "tagName" once implemented.
- assert_equals(elm.localName.toUpperCase(), "NULL", "The tag name should be 'NULL'.");
+ assert_equals(
+ elm.localName.toUpperCase(), "NULL", "The tag name should be 'NULL'.");
}, type + ".querySelector null");
- test(() { // 5
+ test(() {
+ // 5
var elm = root.querySelector('undefined');
assert_not_equals(elm, 'undefined', "This should find an element.");
// TODO(jmesserly): change "localName" back to "tagName" once implemented.
- assert_equals(elm.localName.toUpperCase(), "UNDEFINED", "The tag name should be 'UNDEFINED'.");
+ assert_equals(elm.localName.toUpperCase(),
+ "UNDEFINED", "The tag name should be 'UNDEFINED'.");
}, type + ".querySelector undefined");
- test(() { // 6
+ test(() {
+ // 6
assert_throws((e) => e is NoSuchMethodError, () {
root.querySelector();
}, "This should throw a TypeError.");
}, type + ".querySelector no parameter");
- test(() { // 7
+ test(() {
+ // 7
var result = root.querySelectorAll("*");
var i = 0;
traverse(root, (elem) {
if (!identical(elem, root)) {
- assert_equals(elem, result[i], "The result in index $i should be in tree order.");
+ assert_equals(
+ elem, result[i], "The result in index $i should be in tree order.");
i++;
}
});
@@ -163,7 +184,7 @@
* Execute queries with the specified valid selectors for both querySelector() and querySelectorAll()
* Only run these tests when results are expected. Don't run for syntax error tests.
*/
- runValidSelectorTest(type, root, selectors, testType, docType) {
+runValidSelectorTest(type, root, selectors, testType, docType) {
var nodeType = "";
switch (root.nodeType) {
case Node.DOCUMENT_NODE:
@@ -185,20 +206,26 @@
var q = s["selector"];
var e = s["expect"];
- if ((s["exclude"] is! List || (s["exclude"].indexOf(nodeType) == -1 && s["exclude"].indexOf(docType) == -1))
- && (s["testType"] & testType != 0) ) {
+ if ((s["exclude"] is! List ||
+ (s["exclude"].indexOf(nodeType) == -1 &&
+ s["exclude"].indexOf(docType) == -1)) &&
+ (s["testType"] & testType != 0)) {
//console.log("Running tests " + nodeType + ": " + s["testType"] + "&" + testType + "=" + (s["testType"] & testType) + ": " + JSON.stringify(s))
var foundall, found;
test(() {
foundall = root.querySelectorAll(q);
assert_not_equals(foundall, null, "The method should not return null.");
- assert_equals(foundall.length, e.length, "The method should return the expected number of matches.");
+ assert_equals(foundall.length, e.length,
+ "The method should return the expected number of matches.");
for (var i = 0; i < e.length; i++) {
- assert_not_equals(foundall[i], null, "The item in index $i should not be null.");
- assert_equals(foundall[i].attributes["id"], e[i], "The item in index $i should have the expected ID.");
- assert_false(foundall[i].attributes.containsKey("data-clone"), "This should not be a cloned element.");
+ assert_not_equals(
+ foundall[i], null, "The item in index $i should not be null.");
+ assert_equals(foundall[i].attributes["id"], e[i],
+ "The item in index $i should have the expected ID.");
+ assert_false(foundall[i].attributes.containsKey("data-clone"),
+ "This should not be a cloned element.");
}
}, type + ".querySelectorAll: " + n + ": " + q);
@@ -207,9 +234,12 @@
if (e.length > 0) {
assert_not_equals(found, null, "The method should return a match.");
- assert_equals(found.attributes["id"], e[0], "The method should return the first match.");
- assert_equals(found, foundall[0], "The result should match the first item from querySelectorAll.");
- assert_false(found.attributes.containsKey("data-clone"), "This should not be annotated as a cloned element.");
+ assert_equals(found.attributes["id"], e[0],
+ "The method should return the first match.");
+ assert_equals(found, foundall[0],
+ "The result should match the first item from querySelectorAll.");
+ assert_false(found.attributes.containsKey("data-clone"),
+ "This should not be annotated as a cloned element.");
} else {
assert_equals(found, null, "The method should not match anything.");
}
@@ -224,7 +254,7 @@
* Execute queries with the specified invalid selectors for both querySelector() and querySelectorAll()
* Only run these tests when errors are expected. Don't run for valid selector tests.
*/
- runInvalidSelectorTest(type, root, selectors) {
+runInvalidSelectorTest(type, root, selectors) {
for (var i = 0; i < selectors.length; i++) {
var s = selectors[i];
var n = s["name"];
@@ -245,7 +275,7 @@
}
}
- traverse(Node elem, fn) {
+traverse(Node elem, fn) {
if (elem.nodeType == Node.ELEMENT_NODE) {
fn(elem);
}
@@ -256,7 +286,6 @@
}
}
-
test(Function body, String name) => unittest.test(name, body);
assert_true(value, String reason) =>
@@ -265,8 +294,7 @@
assert_false(value, String reason) =>
unittest.expect(value, false, reason: reason);
-assert_equals(x, y, reason) =>
- unittest.expect(x, y, reason: reason);
+assert_equals(x, y, reason) => unittest.expect(x, y, reason: reason);
assert_not_equals(x, y, reason) =>
unittest.expect(x, unittest.isNot(y), reason: reason);
diff --git a/test/selectors/selectors.dart b/test/selectors/selectors.dart
index fd8bd96..f6ff25d 100644
--- a/test/selectors/selectors.dart
+++ b/test/selectors/selectors.dart
@@ -3,14 +3,17 @@
library html5lib.test.selectors.selectors;
// Bit-mapped flags to indicate which tests the selector is suitable for
-var TEST_QSA_BASELINE = 0x01; // querySelector() and querySelectorAll() baseline tests
-var TEST_QSA_ADDITIONAL = 0x02; // querySelector() and querySelectorAll() additional tests
-var TEST_FIND_BASELINE = 0x04; // find() and findAll() baseline tests, may be unsuitable for querySelector[All]
-var TEST_FIND_ADDITIONAL = 0x08; // find() and findAll() additional tests, may be unsuitable for querySelector[All]
-var TEST_MATCH_BASELINE = 0x10; // matches() baseline tests
+var TEST_QSA_BASELINE =
+ 0x01; // querySelector() and querySelectorAll() baseline tests
+var TEST_QSA_ADDITIONAL =
+ 0x02; // querySelector() and querySelectorAll() additional tests
+var TEST_FIND_BASELINE =
+ 0x04; // find() and findAll() baseline tests, may be unsuitable for querySelector[All]
+var TEST_FIND_ADDITIONAL =
+ 0x08; // find() and findAll() additional tests, may be unsuitable for querySelector[All]
+var TEST_MATCH_BASELINE = 0x10; // matches() baseline tests
var TEST_MATCH_ADDITIONAL = 0x20; // matches() additional tests
-
/*
* All of these invalid selectors should result in a SyntaxError being thrown by the APIs.
*
@@ -18,38 +21,41 @@
* selector: The selector to test
*/
var invalidSelectors = [
- {'name': "Empty String", 'selector': ""},
- {'name': "Invalid character", 'selector': "["},
- {'name': "Invalid character", 'selector': "]"},
- {'name': "Invalid character", 'selector': "("},
- {'name': "Invalid character", 'selector': ")"},
- {'name': "Invalid character", 'selector': "{"},
- {'name': "Invalid character", 'selector': "}"},
- {'name': "Invalid character", 'selector': "<"},
- {'name': "Invalid character", 'selector': ">"},
- {'name': "Invalid ID", 'selector': "#"},
- {'name': "Invalid group of selectors", 'selector': "div,"},
- {'name': "Invalid class", 'selector': "."},
- {'name': "Invalid class", 'selector': ".5cm"},
- {'name': "Invalid class", 'selector': "..test"},
- {'name': "Invalid class", 'selector': ".foo..quux"},
- {'name': "Invalid class", 'selector': ".bar."},
- {'name': "Invalid combinator", 'selector': "div & address, p"},
- {'name': "Invalid combinator", 'selector': "div >> address, p"},
- {'name': "Invalid combinator", 'selector': "div ++ address, p"},
- {'name': "Invalid combinator", 'selector': "div ~~ address, p"},
+ {'name': "Empty String", 'selector': ""},
+ {'name': "Invalid character", 'selector': "["},
+ {'name': "Invalid character", 'selector': "]"},
+ {'name': "Invalid character", 'selector': "("},
+ {'name': "Invalid character", 'selector': ")"},
+ {'name': "Invalid character", 'selector': "{"},
+ {'name': "Invalid character", 'selector': "}"},
+ {'name': "Invalid character", 'selector': "<"},
+ {'name': "Invalid character", 'selector': ">"},
+ {'name': "Invalid ID", 'selector': "#"},
+ {'name': "Invalid group of selectors", 'selector': "div,"},
+ {'name': "Invalid class", 'selector': "."},
+ {'name': "Invalid class", 'selector': ".5cm"},
+ {'name': "Invalid class", 'selector': "..test"},
+ {'name': "Invalid class", 'selector': ".foo..quux"},
+ {'name': "Invalid class", 'selector': ".bar."},
+ {'name': "Invalid combinator", 'selector': "div & address, p"},
+ {'name': "Invalid combinator", 'selector': "div >> address, p"},
+ {'name': "Invalid combinator", 'selector': "div ++ address, p"},
+ {'name': "Invalid combinator", 'selector': "div ~~ address, p"},
{'name': "Invalid [att=value] selector", 'selector': "[*=test]"},
{'name': "Invalid [att=value] selector", 'selector': "[*|*=test]"},
- {'name': "Invalid [att=value] selector", 'selector': "[class= space unquoted ]"},
- {'name': "Unknown pseudo-class", 'selector': "div:example"},
- {'name': "Unknown pseudo-class", 'selector': ":example"},
- {'name': "Unknown pseudo-element", 'selector': "div::example"},
- {'name': "Unknown pseudo-element", 'selector': "::example"},
- {'name': "Invalid pseudo-element", 'selector': ":::before"},
- {'name': "Undeclared namespace", 'selector': "ns|div"},
- {'name': "Undeclared namespace", 'selector': ":not(ns|div)"},
- {'name': "Invalid namespace", 'selector': "^|div"},
- {'name': "Invalid namespace", 'selector': "\$|div"}
+ {
+ 'name': "Invalid [att=value] selector",
+ 'selector': "[class= space unquoted ]"
+ },
+ {'name': "Unknown pseudo-class", 'selector': "div:example"},
+ {'name': "Unknown pseudo-class", 'selector': ":example"},
+ {'name': "Unknown pseudo-element", 'selector': "div::example"},
+ {'name': "Unknown pseudo-element", 'selector': "::example"},
+ {'name': "Invalid pseudo-element", 'selector': ":::before"},
+ {'name': "Undeclared namespace", 'selector': "ns|div"},
+ {'name': "Undeclared namespace", 'selector': ":not(ns|div)"},
+ {'name': "Invalid namespace", 'selector': "^|div"},
+ {'name': "Invalid namespace", 'selector': "\$|div"}
];
/*
@@ -70,294 +76,1800 @@
*/
var validSelectors = [
// Type Selector
- {'name': "Type selector, matching html element", 'selector': "html", 'expect': ["html"], 'exclude': ["element", "fragment", "detached"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Type selector, matching html element", 'selector': "html", 'expect': [] /*no matches*/, 'exclude': ["document"], 'level': 1, 'testType': TEST_QSA_BASELINE},
- {'name': "Type selector, matching body element", 'selector': "body", 'expect': ["body"], 'exclude': ["element", "fragment", "detached"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Type selector, matching body element", 'selector': "body", 'expect': [] /*no matches*/, 'exclude': ["document"], 'level': 1, 'testType': TEST_QSA_BASELINE},
+ {
+ 'name': "Type selector, matching html element",
+ 'selector': "html",
+ 'expect': ["html"],
+ 'exclude': ["element", "fragment", "detached"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "Type selector, matching html element",
+ 'selector': "html",
+ 'expect': [] /*no matches*/,
+ 'exclude': ["document"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name': "Type selector, matching body element",
+ 'selector': "body",
+ 'expect': ["body"],
+ 'exclude': ["element", "fragment", "detached"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "Type selector, matching body element",
+ 'selector': "body",
+ 'expect': [] /*no matches*/,
+ 'exclude': ["document"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE
+ },
// Universal Selector
// Testing "*" for entire an entire context node is handled separately.
- {'name': "Universal selector, matching all children of element with specified ID", 'selector': "#universal>*", 'expect': ["universal-p1", "universal-hr1", "universal-pre1", "universal-p2", "universal-address1"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Universal selector, matching all grandchildren of element with specified ID", 'selector': "#universal>*>*", 'expect': ["universal-code1", "universal-span1", "universal-a1", "universal-code2"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Universal selector, matching all children of empty element with specified ID", 'selector': "#empty>*", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "Universal selector, matching all descendants of element with specified ID", 'selector': "#universal *", 'expect': ["universal-p1", "universal-code1", "universal-hr1", "universal-pre1", "universal-span1", "universal-p2", "universal-a1", "universal-address1", "universal-code2", "universal-a2"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ "Universal selector, matching all children of element with specified ID",
+ 'selector': "#universal>*",
+ 'expect': [
+ "universal-p1",
+ "universal-hr1",
+ "universal-pre1",
+ "universal-p2",
+ "universal-address1"
+ ],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Universal selector, matching all grandchildren of element with specified ID",
+ 'selector': "#universal>*>*",
+ 'expect': [
+ "universal-code1",
+ "universal-span1",
+ "universal-a1",
+ "universal-code2"
+ ],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Universal selector, matching all children of empty element with specified ID",
+ 'selector': "#empty>*",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "Universal selector, matching all descendants of element with specified ID",
+ 'selector': "#universal *",
+ 'expect': [
+ "universal-p1",
+ "universal-code1",
+ "universal-hr1",
+ "universal-pre1",
+ "universal-span1",
+ "universal-p2",
+ "universal-a1",
+ "universal-address1",
+ "universal-code2",
+ "universal-a2"
+ ],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
// Attribute Selectors
// - presence [att]
- {'name': "Attribute presence selector, matching align attribute with value", 'selector': ".attr-presence-div1[align]", 'expect': ["attr-presence-div1"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute presence selector, matching align attribute with empty value", 'selector': ".attr-presence-div2[align]", 'expect': ["attr-presence-div2"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute presence selector, matching title attribute, case insensitivity", 'selector': "#attr-presence [TiTlE]", 'expect': ["attr-presence-a1", "attr-presence-span1"], 'exclude': ["xhtml"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute presence selector, not matching title attribute, case sensitivity", 'selector': "#attr-presence [TiTlE]", 'expect': [], 'exclude': ["html"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute presence selector, matching custom data-* attribute", 'selector': "[data-attr-presence]", 'expect': ["attr-presence-pre1", "attr-presence-blockquote1"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute presence selector, not matching attribute with similar name", 'selector': ".attr-presence-div3[align], .attr-presence-div4[align]", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "Attribute presence selector, matching attribute with non-ASCII characters", 'selector': "ul[data-中文]", 'expect': ["attr-presence-ul1"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute presence selector, not matching default option without selected attribute", 'selector': "#attr-presence-select1 option[selected]", 'expect': [] /* no matches */, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "Attribute presence selector, matching option with selected attribute", 'selector': "#attr-presence-select2 option[selected]", 'expect': ["attr-presence-select2-option4"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute presence selector, matching multiple options with selected attributes", 'selector': "#attr-presence-select3 option[selected]", 'expect': ["attr-presence-select3-option2", "attr-presence-select3-option3"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
+ {
+ 'name': "Attribute presence selector, matching align attribute with value",
+ 'selector': ".attr-presence-div1[align]",
+ 'expect': ["attr-presence-div1"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute presence selector, matching align attribute with empty value",
+ 'selector': ".attr-presence-div2[align]",
+ 'expect': ["attr-presence-div2"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute presence selector, matching title attribute, case insensitivity",
+ 'selector': "#attr-presence [TiTlE]",
+ 'expect': ["attr-presence-a1", "attr-presence-span1"],
+ 'exclude': ["xhtml"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute presence selector, not matching title attribute, case sensitivity",
+ 'selector': "#attr-presence [TiTlE]",
+ 'expect': [],
+ 'exclude': ["html"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "Attribute presence selector, matching custom data-* attribute",
+ 'selector': "[data-attr-presence]",
+ 'expect': ["attr-presence-pre1", "attr-presence-blockquote1"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute presence selector, not matching attribute with similar name",
+ 'selector': ".attr-presence-div3[align], .attr-presence-div4[align]",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "Attribute presence selector, matching attribute with non-ASCII characters",
+ 'selector': "ul[data-中文]",
+ 'expect': ["attr-presence-ul1"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute presence selector, not matching default option without selected attribute",
+ 'selector': "#attr-presence-select1 option[selected]",
+ 'expect': [] /* no matches */,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "Attribute presence selector, matching option with selected attribute",
+ 'selector': "#attr-presence-select2 option[selected]",
+ 'expect': ["attr-presence-select2-option4"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute presence selector, matching multiple options with selected attributes",
+ 'selector': "#attr-presence-select3 option[selected]",
+ 'expect': [
+ "attr-presence-select3-option2",
+ "attr-presence-select3-option3"
+ ],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
// - value [att=val]
- {'name': "Attribute value selector, matching align attribute with value", 'selector': "#attr-value [align=\"center\"]", 'expect': ["attr-value-div1"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute value selector, matching align attribute with empty value", 'selector': "#attr-value [align=\"\"]", 'expect': ["attr-value-div2"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute value selector, not matching align attribute with partial value", 'selector': "#attr-value [align=\"c\"]", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "Attribute value selector, not matching align attribute with incorrect value", 'selector': "#attr-value [align=\"centera\"]", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "Attribute value selector, matching custom data-* attribute with unicode escaped value", 'selector': "[data-attr-value=\"\\e9\"]", 'expect': ["attr-value-div3"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute value selector, matching custom data-* attribute with escaped character", 'selector': "[data-attr-value\_foo=\"\\e9\"]", 'expect': ["attr-value-div4"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute value selector with single-quoted value, matching multiple inputs with type attributes", 'selector': "#attr-value input[type='hidden'],#attr-value input[type='radio']", 'expect': ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute value selector with double-quoted value, matching multiple inputs with type attributes", 'selector': "#attr-value input[type=\"hidden\"],#attr-value input[type='radio']", 'expect': ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute value selector with unquoted value, matching multiple inputs with type attributes", 'selector': "#attr-value input[type=hidden],#attr-value input[type=radio]", 'expect': ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute value selector, matching attribute with value using non-ASCII characters", 'selector': "[data-attr-value=中文]", 'expect': ["attr-value-div5"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
+ {
+ 'name': "Attribute value selector, matching align attribute with value",
+ 'selector': "#attr-value [align=\"center\"]",
+ 'expect': ["attr-value-div1"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute value selector, matching align attribute with empty value",
+ 'selector': "#attr-value [align=\"\"]",
+ 'expect': ["attr-value-div2"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute value selector, not matching align attribute with partial value",
+ 'selector': "#attr-value [align=\"c\"]",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "Attribute value selector, not matching align attribute with incorrect value",
+ 'selector': "#attr-value [align=\"centera\"]",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "Attribute value selector, matching custom data-* attribute with unicode escaped value",
+ 'selector': "[data-attr-value=\"\\e9\"]",
+ 'expect': ["attr-value-div3"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute value selector, matching custom data-* attribute with escaped character",
+ 'selector': "[data-attr-value\_foo=\"\\e9\"]",
+ 'expect': ["attr-value-div4"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute value selector with single-quoted value, matching multiple inputs with type attributes",
+ 'selector':
+ "#attr-value input[type='hidden'],#attr-value input[type='radio']",
+ 'expect': [
+ "attr-value-input3",
+ "attr-value-input4",
+ "attr-value-input6",
+ "attr-value-input8",
+ "attr-value-input9"
+ ],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute value selector with double-quoted value, matching multiple inputs with type attributes",
+ 'selector':
+ "#attr-value input[type=\"hidden\"],#attr-value input[type='radio']",
+ 'expect': [
+ "attr-value-input3",
+ "attr-value-input4",
+ "attr-value-input6",
+ "attr-value-input8",
+ "attr-value-input9"
+ ],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute value selector with unquoted value, matching multiple inputs with type attributes",
+ 'selector': "#attr-value input[type=hidden],#attr-value input[type=radio]",
+ 'expect': [
+ "attr-value-input3",
+ "attr-value-input4",
+ "attr-value-input6",
+ "attr-value-input8",
+ "attr-value-input9"
+ ],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute value selector, matching attribute with value using non-ASCII characters",
+ 'selector': "[data-attr-value=中文]",
+ 'expect': ["attr-value-div5"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
// - whitespace-separated list [att~=val]
- {'name': "Attribute whitespace-separated list selector, matching class attribute with value", 'selector': "#attr-whitespace [class~=\"div1\"]", 'expect': ["attr-whitespace-div1"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute whitespace-separated list selector, not matching class attribute with empty value", 'selector': "#attr-whitespace [class~=\"\"]", 'expect': [] /*no matches*/ , 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "Attribute whitespace-separated list selector, not matching class attribute with partial value", 'selector': "[data-attr-whitespace~=\"div\"]", 'expect': [] /*no matches*/ , 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "Attribute whitespace-separated list selector, matching custom data-* attribute with unicode escaped value", 'selector': "[data-attr-whitespace~=\"\\0000e9\"]", 'expect': ["attr-whitespace-div4"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute whitespace-separated list selector, matching custom data-* attribute with escaped character", 'selector': "[data-attr-whitespace\_foo~=\"\\e9\"]", 'expect': ["attr-whitespace-div5"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute whitespace-separated list selector with single-quoted value, matching multiple links with rel attributes", 'selector': "#attr-whitespace a[rel~='bookmark'], #attr-whitespace a[rel~='nofollow']", 'expect': ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute whitespace-separated list selector with double-quoted value, matching multiple links with rel attributes", 'selector': "#attr-whitespace a[rel~=\"bookmark\"],#attr-whitespace a[rel~='nofollow']", 'expect': ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute whitespace-separated list selector with unquoted value, matching multiple links with rel attributes", 'selector': "#attr-whitespace a[rel~=bookmark], #attr-whitespace a[rel~=nofollow]", 'expect': ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute whitespace-separated list selector with double-quoted value, not matching value with space", 'selector': "#attr-whitespace a[rel~=\"book mark\"]", 'expect': [] /* no matches */, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "Attribute whitespace-separated list selector, matching title attribute with value using non-ASCII characters", 'selector': "#attr-whitespace [title~=中文]", 'expect': ["attr-whitespace-p1"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ "Attribute whitespace-separated list selector, matching class attribute with value",
+ 'selector': "#attr-whitespace [class~=\"div1\"]",
+ 'expect': ["attr-whitespace-div1"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute whitespace-separated list selector, not matching class attribute with empty value",
+ 'selector': "#attr-whitespace [class~=\"\"]",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "Attribute whitespace-separated list selector, not matching class attribute with partial value",
+ 'selector': "[data-attr-whitespace~=\"div\"]",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "Attribute whitespace-separated list selector, matching custom data-* attribute with unicode escaped value",
+ 'selector': "[data-attr-whitespace~=\"\\0000e9\"]",
+ 'expect': ["attr-whitespace-div4"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute whitespace-separated list selector, matching custom data-* attribute with escaped character",
+ 'selector': "[data-attr-whitespace\_foo~=\"\\e9\"]",
+ 'expect': ["attr-whitespace-div5"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute whitespace-separated list selector with single-quoted value, matching multiple links with rel attributes",
+ 'selector':
+ "#attr-whitespace a[rel~='bookmark'], #attr-whitespace a[rel~='nofollow']",
+ 'expect': [
+ "attr-whitespace-a1",
+ "attr-whitespace-a2",
+ "attr-whitespace-a3",
+ "attr-whitespace-a5",
+ "attr-whitespace-a7"
+ ],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute whitespace-separated list selector with double-quoted value, matching multiple links with rel attributes",
+ 'selector':
+ "#attr-whitespace a[rel~=\"bookmark\"],#attr-whitespace a[rel~='nofollow']",
+ 'expect': [
+ "attr-whitespace-a1",
+ "attr-whitespace-a2",
+ "attr-whitespace-a3",
+ "attr-whitespace-a5",
+ "attr-whitespace-a7"
+ ],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute whitespace-separated list selector with unquoted value, matching multiple links with rel attributes",
+ 'selector':
+ "#attr-whitespace a[rel~=bookmark], #attr-whitespace a[rel~=nofollow]",
+ 'expect': [
+ "attr-whitespace-a1",
+ "attr-whitespace-a2",
+ "attr-whitespace-a3",
+ "attr-whitespace-a5",
+ "attr-whitespace-a7"
+ ],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute whitespace-separated list selector with double-quoted value, not matching value with space",
+ 'selector': "#attr-whitespace a[rel~=\"book mark\"]",
+ 'expect': [] /* no matches */,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "Attribute whitespace-separated list selector, matching title attribute with value using non-ASCII characters",
+ 'selector': "#attr-whitespace [title~=中文]",
+ 'expect': ["attr-whitespace-p1"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
// - hyphen-separated list [att|=val]
- {'name': "Attribute hyphen-separated list selector, not matching unspecified lang attribute", 'selector': "#attr-hyphen-div1[lang|=\"en\"]", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "Attribute hyphen-separated list selector, matching lang attribute with exact value", 'selector': "#attr-hyphen-div2[lang|=\"fr\"]", 'expect': ["attr-hyphen-div2"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute hyphen-separated list selector, matching lang attribute with partial value", 'selector': "#attr-hyphen-div3[lang|=\"en\"]", 'expect': ["attr-hyphen-div3"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Attribute hyphen-separated list selector, not matching incorrect value", 'selector': "#attr-hyphen-div4[lang|=\"es-AR\"]", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
+ {
+ 'name':
+ "Attribute hyphen-separated list selector, not matching unspecified lang attribute",
+ 'selector': "#attr-hyphen-div1[lang|=\"en\"]",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "Attribute hyphen-separated list selector, matching lang attribute with exact value",
+ 'selector': "#attr-hyphen-div2[lang|=\"fr\"]",
+ 'expect': ["attr-hyphen-div2"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute hyphen-separated list selector, matching lang attribute with partial value",
+ 'selector': "#attr-hyphen-div3[lang|=\"en\"]",
+ 'expect': ["attr-hyphen-div3"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute hyphen-separated list selector, not matching incorrect value",
+ 'selector': "#attr-hyphen-div4[lang|=\"es-AR\"]",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
// - substring begins-with [att^=val] (Level 3)
- {'name': "Attribute begins with selector, matching href attributes beginning with specified substring", 'selector': "#attr-begins a[href^=\"http://www\"]", 'expect': ["attr-begins-a1", "attr-begins-a3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute begins with selector, matching lang attributes beginning with specified substring, ", 'selector': "#attr-begins [lang^=\"en-\"]", 'expect': ["attr-begins-div2", "attr-begins-div4"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute begins with selector, not matching class attribute not beginning with specified substring", 'selector': "#attr-begins [class^=apple]", 'expect': [] /*no matches*/, 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
- {'name': "Attribute begins with selector with single-quoted value, matching class attribute beginning with specified substring", 'selector': "#attr-begins [class^=' apple']", 'expect': ["attr-begins-p1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute begins with selector with double-quoted value, matching class attribute beginning with specified substring", 'selector': "#attr-begins [class^=\" apple\"]", 'expect': ["attr-begins-p1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute begins with selector with unquoted value, not matching class attribute not beginning with specified substring", 'selector': "#attr-begins [class^= apple]", 'expect': [] /*no matches*/, 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
+ {
+ 'name':
+ "Attribute begins with selector, matching href attributes beginning with specified substring",
+ 'selector': "#attr-begins a[href^=\"http://www\"]",
+ 'expect': ["attr-begins-a1", "attr-begins-a3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute begins with selector, matching lang attributes beginning with specified substring, ",
+ 'selector': "#attr-begins [lang^=\"en-\"]",
+ 'expect': ["attr-begins-div2", "attr-begins-div4"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute begins with selector, not matching class attribute not beginning with specified substring",
+ 'selector': "#attr-begins [class^=apple]",
+ 'expect': [] /*no matches*/,
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
+ {
+ 'name':
+ "Attribute begins with selector with single-quoted value, matching class attribute beginning with specified substring",
+ 'selector': "#attr-begins [class^=' apple']",
+ 'expect': ["attr-begins-p1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute begins with selector with double-quoted value, matching class attribute beginning with specified substring",
+ 'selector': "#attr-begins [class^=\" apple\"]",
+ 'expect': ["attr-begins-p1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute begins with selector with unquoted value, not matching class attribute not beginning with specified substring",
+ 'selector': "#attr-begins [class^= apple]",
+ 'expect': [] /*no matches*/,
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
// - substring ends-with [att\$=val] (Level 3)
- {'name': "Attribute ends with selector, matching href attributes ending with specified substring", 'selector': "#attr-ends a[href\$=\".org\"]", 'expect': ["attr-ends-a1", "attr-ends-a3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute ends with selector, matching lang attributes ending with specified substring, ", 'selector': "#attr-ends [lang\$=\"-CH\"]", 'expect': ["attr-ends-div2", "attr-ends-div4"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute ends with selector, not matching class attribute not ending with specified substring", 'selector': "#attr-ends [class\$=apple]", 'expect': [] /*no matches*/, 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
- {'name': "Attribute ends with selector with single-quoted value, matching class attribute ending with specified substring", 'selector': "#attr-ends [class\$='apple ']", 'expect': ["attr-ends-p1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute ends with selector with double-quoted value, matching class attribute ending with specified substring", 'selector': "#attr-ends [class\$=\"apple \"]", 'expect': ["attr-ends-p1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute ends with selector with unquoted value, not matching class attribute not ending with specified substring", 'selector': "#attr-ends [class\$=apple ]", 'expect': [] /*no matches*/, 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
+ {
+ 'name':
+ "Attribute ends with selector, matching href attributes ending with specified substring",
+ 'selector': "#attr-ends a[href\$=\".org\"]",
+ 'expect': ["attr-ends-a1", "attr-ends-a3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute ends with selector, matching lang attributes ending with specified substring, ",
+ 'selector': "#attr-ends [lang\$=\"-CH\"]",
+ 'expect': ["attr-ends-div2", "attr-ends-div4"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute ends with selector, not matching class attribute not ending with specified substring",
+ 'selector': "#attr-ends [class\$=apple]",
+ 'expect': [] /*no matches*/,
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
+ {
+ 'name':
+ "Attribute ends with selector with single-quoted value, matching class attribute ending with specified substring",
+ 'selector': "#attr-ends [class\$='apple ']",
+ 'expect': ["attr-ends-p1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute ends with selector with double-quoted value, matching class attribute ending with specified substring",
+ 'selector': "#attr-ends [class\$=\"apple \"]",
+ 'expect': ["attr-ends-p1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute ends with selector with unquoted value, not matching class attribute not ending with specified substring",
+ 'selector': "#attr-ends [class\$=apple ]",
+ 'expect': [] /*no matches*/,
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
// - substring contains [att*=val] (Level 3)
- {'name': "Attribute contains selector, matching href attributes beginning with specified substring", 'selector': "#attr-contains a[href*=\"http://www\"]", 'expect': ["attr-contains-a1", "attr-contains-a3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute contains selector, matching href attributes ending with specified substring", 'selector': "#attr-contains a[href*=\".org\"]", 'expect': ["attr-contains-a1", "attr-contains-a2"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute contains selector, matching href attributes containing specified substring", 'selector': "#attr-contains a[href*=\".example.\"]", 'expect': ["attr-contains-a1", "attr-contains-a3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute contains selector, matching lang attributes beginning with specified substring, ", 'selector': "#attr-contains [lang*=\"en-\"]", 'expect': ["attr-contains-div2", "attr-contains-div6"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute contains selector, matching lang attributes ending with specified substring, ", 'selector': "#attr-contains [lang*=\"-CH\"]", 'expect': ["attr-contains-div3", "attr-contains-div5"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute contains selector with single-quoted value, matching class attribute beginning with specified substring", 'selector': "#attr-contains [class*=' apple']", 'expect': ["attr-contains-p1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute contains selector with single-quoted value, matching class attribute ending with specified substring", 'selector': "#attr-contains [class*='orange ']", 'expect': ["attr-contains-p1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute contains selector with single-quoted value, matching class attribute containing specified substring", 'selector': "#attr-contains [class*='ple banana ora']", 'expect': ["attr-contains-p1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute contains selector with double-quoted value, matching class attribute beginning with specified substring", 'selector': "#attr-contains [class*=\" apple\"]", 'expect': ["attr-contains-p1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute contains selector with double-quoted value, matching class attribute ending with specified substring", 'selector': "#attr-contains [class*=\"orange \"]", 'expect': ["attr-contains-p1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute contains selector with double-quoted value, matching class attribute containing specified substring", 'selector': "#attr-contains [class*=\"ple banana ora\"]", 'expect': ["attr-contains-p1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute contains selector with unquoted value, matching class attribute beginning with specified substring", 'selector': "#attr-contains [class*= apple]", 'expect': ["attr-contains-p1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute contains selector with unquoted value, matching class attribute ending with specified substring", 'selector': "#attr-contains [class*=orange ]", 'expect': ["attr-contains-p1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "Attribute contains selector with unquoted value, matching class attribute containing specified substring", 'selector': "#attr-contains [class*= banana ]", 'expect': ["attr-contains-p1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ "Attribute contains selector, matching href attributes beginning with specified substring",
+ 'selector': "#attr-contains a[href*=\"http://www\"]",
+ 'expect': ["attr-contains-a1", "attr-contains-a3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute contains selector, matching href attributes ending with specified substring",
+ 'selector': "#attr-contains a[href*=\".org\"]",
+ 'expect': ["attr-contains-a1", "attr-contains-a2"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute contains selector, matching href attributes containing specified substring",
+ 'selector': "#attr-contains a[href*=\".example.\"]",
+ 'expect': ["attr-contains-a1", "attr-contains-a3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute contains selector, matching lang attributes beginning with specified substring, ",
+ 'selector': "#attr-contains [lang*=\"en-\"]",
+ 'expect': ["attr-contains-div2", "attr-contains-div6"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute contains selector, matching lang attributes ending with specified substring, ",
+ 'selector': "#attr-contains [lang*=\"-CH\"]",
+ 'expect': ["attr-contains-div3", "attr-contains-div5"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute contains selector with single-quoted value, matching class attribute beginning with specified substring",
+ 'selector': "#attr-contains [class*=' apple']",
+ 'expect': ["attr-contains-p1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute contains selector with single-quoted value, matching class attribute ending with specified substring",
+ 'selector': "#attr-contains [class*='orange ']",
+ 'expect': ["attr-contains-p1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute contains selector with single-quoted value, matching class attribute containing specified substring",
+ 'selector': "#attr-contains [class*='ple banana ora']",
+ 'expect': ["attr-contains-p1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute contains selector with double-quoted value, matching class attribute beginning with specified substring",
+ 'selector': "#attr-contains [class*=\" apple\"]",
+ 'expect': ["attr-contains-p1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute contains selector with double-quoted value, matching class attribute ending with specified substring",
+ 'selector': "#attr-contains [class*=\"orange \"]",
+ 'expect': ["attr-contains-p1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute contains selector with double-quoted value, matching class attribute containing specified substring",
+ 'selector': "#attr-contains [class*=\"ple banana ora\"]",
+ 'expect': ["attr-contains-p1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute contains selector with unquoted value, matching class attribute beginning with specified substring",
+ 'selector': "#attr-contains [class*= apple]",
+ 'expect': ["attr-contains-p1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute contains selector with unquoted value, matching class attribute ending with specified substring",
+ 'selector': "#attr-contains [class*=orange ]",
+ 'expect': ["attr-contains-p1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Attribute contains selector with unquoted value, matching class attribute containing specified substring",
+ 'selector': "#attr-contains [class*= banana ]",
+ 'expect': ["attr-contains-p1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// Pseudo-classes
// - :root (Level 3)
- {'name': ":root pseudo-class selector, matching document root element", 'selector': ":root", 'expect': ["html"], 'exclude': ["element", "fragment", "detached"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":root pseudo-class selector, not matching document root element", 'selector': ":root", 'expect': [] /*no matches*/, 'exclude': ["document"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
+ {
+ 'name': ":root pseudo-class selector, matching document root element",
+ 'selector': ":root",
+ 'expect': ["html"],
+ 'exclude': ["element", "fragment", "detached"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': ":root pseudo-class selector, not matching document root element",
+ 'selector': ":root",
+ 'expect': [] /*no matches*/,
+ 'exclude': ["document"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
// - :nth-child(n) (Level 3)
- {'name': ":nth-child selector, matching the third child element", 'selector': "#pseudo-nth-table1 :nth-child(3)", 'expect': ["pseudo-nth-td3", "pseudo-nth-td9", "pseudo-nth-tr3", "pseudo-nth-td15"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":nth-child selector, matching every third child element", 'selector': "#pseudo-nth li:nth-child(3n)", 'expect': ["pseudo-nth-li3", "pseudo-nth-li6", "pseudo-nth-li9", "pseudo-nth-li12"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":nth-child selector, matching every second child element, starting from the fourth", 'selector': "#pseudo-nth li:nth-child(2n+4)", 'expect': ["pseudo-nth-li4", "pseudo-nth-li6", "pseudo-nth-li8", "pseudo-nth-li10", "pseudo-nth-li12"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":nth-child selector, matching every fourth child element, starting from the third", 'selector': "#pseudo-nth-p1 :nth-child(4n-1)", 'expect': ["pseudo-nth-em2", "pseudo-nth-span3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name': ":nth-child selector, matching the third child element",
+ 'selector': "#pseudo-nth-table1 :nth-child(3)",
+ 'expect': [
+ "pseudo-nth-td3",
+ "pseudo-nth-td9",
+ "pseudo-nth-tr3",
+ "pseudo-nth-td15"
+ ],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': ":nth-child selector, matching every third child element",
+ 'selector': "#pseudo-nth li:nth-child(3n)",
+ 'expect': [
+ "pseudo-nth-li3",
+ "pseudo-nth-li6",
+ "pseudo-nth-li9",
+ "pseudo-nth-li12"
+ ],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":nth-child selector, matching every second child element, starting from the fourth",
+ 'selector': "#pseudo-nth li:nth-child(2n+4)",
+ 'expect': [
+ "pseudo-nth-li4",
+ "pseudo-nth-li6",
+ "pseudo-nth-li8",
+ "pseudo-nth-li10",
+ "pseudo-nth-li12"
+ ],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":nth-child selector, matching every fourth child element, starting from the third",
+ 'selector': "#pseudo-nth-p1 :nth-child(4n-1)",
+ 'expect': ["pseudo-nth-em2", "pseudo-nth-span3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// - :nth-last-child (Level 3)
- {'name': ":nth-last-child selector, matching the third last child element", 'selector': "#pseudo-nth-table1 :nth-last-child(3)", 'expect': ["pseudo-nth-tr1", "pseudo-nth-td4", "pseudo-nth-td10", "pseudo-nth-td16"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":nth-last-child selector, matching every third child element from the end", 'selector': "#pseudo-nth li:nth-last-child(3n)", 'expect': ["pseudo-nth-li1", "pseudo-nth-li4", "pseudo-nth-li7", "pseudo-nth-li10"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":nth-last-child selector, matching every second child element from the end, starting from the fourth last", 'selector': "#pseudo-nth li:nth-last-child(2n+4)", 'expect': ["pseudo-nth-li1", "pseudo-nth-li3", "pseudo-nth-li5", "pseudo-nth-li7", "pseudo-nth-li9"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":nth-last-child selector, matching every fourth element from the end, starting from the third last", 'selector': "#pseudo-nth-p1 :nth-last-child(4n-1)", 'expect': ["pseudo-nth-span2", "pseudo-nth-span4"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name': ":nth-last-child selector, matching the third last child element",
+ 'selector': "#pseudo-nth-table1 :nth-last-child(3)",
+ 'expect': [
+ "pseudo-nth-tr1",
+ "pseudo-nth-td4",
+ "pseudo-nth-td10",
+ "pseudo-nth-td16"
+ ],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":nth-last-child selector, matching every third child element from the end",
+ 'selector': "#pseudo-nth li:nth-last-child(3n)",
+ 'expect': [
+ "pseudo-nth-li1",
+ "pseudo-nth-li4",
+ "pseudo-nth-li7",
+ "pseudo-nth-li10"
+ ],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":nth-last-child selector, matching every second child element from the end, starting from the fourth last",
+ 'selector': "#pseudo-nth li:nth-last-child(2n+4)",
+ 'expect': [
+ "pseudo-nth-li1",
+ "pseudo-nth-li3",
+ "pseudo-nth-li5",
+ "pseudo-nth-li7",
+ "pseudo-nth-li9"
+ ],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":nth-last-child selector, matching every fourth element from the end, starting from the third last",
+ 'selector': "#pseudo-nth-p1 :nth-last-child(4n-1)",
+ 'expect': ["pseudo-nth-span2", "pseudo-nth-span4"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// - :nth-of-type(n) (Level 3)
- {'name': ":nth-of-type selector, matching the third em element", 'selector': "#pseudo-nth-p1 em:nth-of-type(3)", 'expect': ["pseudo-nth-em3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":nth-of-type selector, matching every second element of their type", 'selector': "#pseudo-nth-p1 :nth-of-type(2n)", 'expect': ["pseudo-nth-em2", "pseudo-nth-span2", "pseudo-nth-span4", "pseudo-nth-strong2", "pseudo-nth-em4"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":nth-of-type selector, matching every second elemetn of their type, starting from the first", 'selector': "#pseudo-nth-p1 span:nth-of-type(2n-1)", 'expect': ["pseudo-nth-span1", "pseudo-nth-span3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name': ":nth-of-type selector, matching the third em element",
+ 'selector': "#pseudo-nth-p1 em:nth-of-type(3)",
+ 'expect': ["pseudo-nth-em3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":nth-of-type selector, matching every second element of their type",
+ 'selector': "#pseudo-nth-p1 :nth-of-type(2n)",
+ 'expect': [
+ "pseudo-nth-em2",
+ "pseudo-nth-span2",
+ "pseudo-nth-span4",
+ "pseudo-nth-strong2",
+ "pseudo-nth-em4"
+ ],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":nth-of-type selector, matching every second elemetn of their type, starting from the first",
+ 'selector': "#pseudo-nth-p1 span:nth-of-type(2n-1)",
+ 'expect': ["pseudo-nth-span1", "pseudo-nth-span3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// - :nth-last-of-type(n) (Level 3)
- {'name': ":nth-last-of-type selector, matching the thrid last em element", 'selector': "#pseudo-nth-p1 em:nth-last-of-type(3)", 'expect': ["pseudo-nth-em2"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":nth-last-of-type selector, matching every second last element of their type", 'selector': "#pseudo-nth-p1 :nth-last-of-type(2n)", 'expect': ["pseudo-nth-span1", "pseudo-nth-em1", "pseudo-nth-strong1", "pseudo-nth-em3", "pseudo-nth-span3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":nth-last-of-type selector, matching every second last element of their type, starting from the last", 'selector': "#pseudo-nth-p1 span:nth-last-of-type(2n-1)", 'expect': ["pseudo-nth-span2", "pseudo-nth-span4"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name': ":nth-last-of-type selector, matching the thrid last em element",
+ 'selector': "#pseudo-nth-p1 em:nth-last-of-type(3)",
+ 'expect': ["pseudo-nth-em2"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":nth-last-of-type selector, matching every second last element of their type",
+ 'selector': "#pseudo-nth-p1 :nth-last-of-type(2n)",
+ 'expect': [
+ "pseudo-nth-span1",
+ "pseudo-nth-em1",
+ "pseudo-nth-strong1",
+ "pseudo-nth-em3",
+ "pseudo-nth-span3"
+ ],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":nth-last-of-type selector, matching every second last element of their type, starting from the last",
+ 'selector': "#pseudo-nth-p1 span:nth-last-of-type(2n-1)",
+ 'expect': ["pseudo-nth-span2", "pseudo-nth-span4"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// - :first-of-type (Level 3)
- {'name': ":first-of-type selector, matching the first em element", 'selector': "#pseudo-nth-p1 em:first-of-type", 'expect': ["pseudo-nth-em1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":first-of-type selector, matching the first of every type of element", 'selector': "#pseudo-nth-p1 :first-of-type", 'expect': ["pseudo-nth-span1", "pseudo-nth-em1", "pseudo-nth-strong1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":first-of-type selector, matching the first td element in each table row", 'selector': "#pseudo-nth-table1 tr :first-of-type", 'expect': ["pseudo-nth-td1", "pseudo-nth-td7", "pseudo-nth-td13"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name': ":first-of-type selector, matching the first em element",
+ 'selector': "#pseudo-nth-p1 em:first-of-type",
+ 'expect': ["pseudo-nth-em1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":first-of-type selector, matching the first of every type of element",
+ 'selector': "#pseudo-nth-p1 :first-of-type",
+ 'expect': ["pseudo-nth-span1", "pseudo-nth-em1", "pseudo-nth-strong1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":first-of-type selector, matching the first td element in each table row",
+ 'selector': "#pseudo-nth-table1 tr :first-of-type",
+ 'expect': ["pseudo-nth-td1", "pseudo-nth-td7", "pseudo-nth-td13"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// - :last-of-type (Level 3)
- {'name': ":last-of-type selector, matching the last em elemnet", 'selector': "#pseudo-nth-p1 em:last-of-type", 'expect': ["pseudo-nth-em4"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":last-of-type selector, matching the last of every type of element", 'selector': "#pseudo-nth-p1 :last-of-type", 'expect': ["pseudo-nth-span4", "pseudo-nth-strong2", "pseudo-nth-em4"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":last-of-type selector, matching the last td element in each table row", 'selector': "#pseudo-nth-table1 tr :last-of-type", 'expect': ["pseudo-nth-td6", "pseudo-nth-td12", "pseudo-nth-td18"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name': ":last-of-type selector, matching the last em elemnet",
+ 'selector': "#pseudo-nth-p1 em:last-of-type",
+ 'expect': ["pseudo-nth-em4"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":last-of-type selector, matching the last of every type of element",
+ 'selector': "#pseudo-nth-p1 :last-of-type",
+ 'expect': ["pseudo-nth-span4", "pseudo-nth-strong2", "pseudo-nth-em4"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":last-of-type selector, matching the last td element in each table row",
+ 'selector': "#pseudo-nth-table1 tr :last-of-type",
+ 'expect': ["pseudo-nth-td6", "pseudo-nth-td12", "pseudo-nth-td18"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// - :first-child
- {'name': ":first-child pseudo-class selector, matching first child div element", 'selector': "#pseudo-first-child div:first-child", 'expect': ["pseudo-first-child-div1"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': ":first-child pseudo-class selector, doesn't match non-first-child elements", 'selector': ".pseudo-first-child-div2:first-child, .pseudo-first-child-div3:first-child", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': ":first-child pseudo-class selector, matching first-child of multiple elements", 'selector': "#pseudo-first-child span:first-child", 'expect': ["pseudo-first-child-span1", "pseudo-first-child-span3", "pseudo-first-child-span5"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ ":first-child pseudo-class selector, matching first child div element",
+ 'selector': "#pseudo-first-child div:first-child",
+ 'expect': ["pseudo-first-child-div1"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":first-child pseudo-class selector, doesn't match non-first-child elements",
+ 'selector':
+ ".pseudo-first-child-div2:first-child, .pseudo-first-child-div3:first-child",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ ":first-child pseudo-class selector, matching first-child of multiple elements",
+ 'selector': "#pseudo-first-child span:first-child",
+ 'expect': [
+ "pseudo-first-child-span1",
+ "pseudo-first-child-span3",
+ "pseudo-first-child-span5"
+ ],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
// - :last-child (Level 3)
- {'name': ":last-child pseudo-class selector, matching last child div element", 'selector': "#pseudo-last-child div:last-child", 'expect': ["pseudo-last-child-div3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":last-child pseudo-class selector, doesn't match non-last-child elements", 'selector': ".pseudo-last-child-div1:last-child, .pseudo-last-child-div2:first-child", 'expect': [] /*no matches*/, 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
- {'name': ":last-child pseudo-class selector, matching first-child of multiple elements", 'selector': "#pseudo-last-child span:last-child", 'expect': ["pseudo-last-child-span2", "pseudo-last-child-span4", "pseudo-last-child-span6"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ ":last-child pseudo-class selector, matching last child div element",
+ 'selector': "#pseudo-last-child div:last-child",
+ 'expect': ["pseudo-last-child-div3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":last-child pseudo-class selector, doesn't match non-last-child elements",
+ 'selector':
+ ".pseudo-last-child-div1:last-child, .pseudo-last-child-div2:first-child",
+ 'expect': [] /*no matches*/,
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
+ {
+ 'name':
+ ":last-child pseudo-class selector, matching first-child of multiple elements",
+ 'selector': "#pseudo-last-child span:last-child",
+ 'expect': [
+ "pseudo-last-child-span2",
+ "pseudo-last-child-span4",
+ "pseudo-last-child-span6"
+ ],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// - :only-child (Level 3)
- {'name': ":pseudo-only-child pseudo-class selector, matching all only-child elements", 'selector': "#pseudo-only :only-child", 'expect': ["pseudo-only-span1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":pseudo-only-child pseudo-class selector, matching only-child em elements", 'selector': "#pseudo-only em:only-child", 'expect': [] /*no matches*/, 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
+ {
+ 'name':
+ ":pseudo-only-child pseudo-class selector, matching all only-child elements",
+ 'selector': "#pseudo-only :only-child",
+ 'expect': ["pseudo-only-span1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":pseudo-only-child pseudo-class selector, matching only-child em elements",
+ 'selector': "#pseudo-only em:only-child",
+ 'expect': [] /*no matches*/,
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
// - :only-of-type (Level 3)
- {'name': ":pseudo-only-of-type pseudo-class selector, matching all elements with no siblings of the same type", 'selector': "#pseudo-only :only-of-type", 'expect': ["pseudo-only-span1", "pseudo-only-em1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":pseudo-only-of-type pseudo-class selector, matching em elements with no siblings of the same type", 'selector': "#pseudo-only em:only-of-type", 'expect': ["pseudo-only-em1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ ":pseudo-only-of-type pseudo-class selector, matching all elements with no siblings of the same type",
+ 'selector': "#pseudo-only :only-of-type",
+ 'expect': ["pseudo-only-span1", "pseudo-only-em1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":pseudo-only-of-type pseudo-class selector, matching em elements with no siblings of the same type",
+ 'selector': "#pseudo-only em:only-of-type",
+ 'expect': ["pseudo-only-em1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// - :empty (Level 3)
- {'name': ":empty pseudo-class selector, matching empty p elements", 'selector': "#pseudo-empty p:empty", 'expect': ["pseudo-empty-p1", "pseudo-empty-p2"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":empty pseudo-class selector, matching all empty elements", 'selector': "#pseudo-empty :empty", 'expect': ["pseudo-empty-p1", "pseudo-empty-p2", "pseudo-empty-span1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name': ":empty pseudo-class selector, matching empty p elements",
+ 'selector': "#pseudo-empty p:empty",
+ 'expect': ["pseudo-empty-p1", "pseudo-empty-p2"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': ":empty pseudo-class selector, matching all empty elements",
+ 'selector': "#pseudo-empty :empty",
+ 'expect': ["pseudo-empty-p1", "pseudo-empty-p2", "pseudo-empty-span1"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// - :link and :visited
// Implementations may treat all visited links as unvisited, so these cannot be tested separately.
// The only guarantee is that ":link,:visited" matches the set of all visited and unvisited links and that they are individually mutually exclusive sets.
- {'name': ":link and :visited pseudo-class selectors, matching a and area elements with href attributes", 'selector': "#pseudo-link :link, #pseudo-link :visited", 'expect': ["pseudo-link-a1", "pseudo-link-a2", "pseudo-link-area1"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': ":link and :visited pseudo-class selectors, matching link elements with href attributes", 'selector': "#head :link, #head :visited", 'expect': ["pseudo-link-link1", "pseudo-link-link2"], 'exclude': ["element", "fragment", "detached"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': ":link and :visited pseudo-class selectors, not matching link elements with href attributes", 'selector': "#head :link, #head :visited", 'expect': [] /*no matches*/, 'exclude': ["document"], 'level': 1, 'testType': TEST_QSA_BASELINE},
- {'name': ":link and :visited pseudo-class selectors, chained, mutually exclusive pseudo-classes match nothing", 'selector': ":link:visited", 'expect': [] /*no matches*/, 'exclude': ["document"], 'level': 1, 'testType': TEST_QSA_BASELINE},
+ {
+ 'name':
+ ":link and :visited pseudo-class selectors, matching a and area elements with href attributes",
+ 'selector': "#pseudo-link :link, #pseudo-link :visited",
+ 'expect': ["pseudo-link-a1", "pseudo-link-a2", "pseudo-link-area1"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":link and :visited pseudo-class selectors, matching link elements with href attributes",
+ 'selector': "#head :link, #head :visited",
+ 'expect': ["pseudo-link-link1", "pseudo-link-link2"],
+ 'exclude': ["element", "fragment", "detached"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":link and :visited pseudo-class selectors, not matching link elements with href attributes",
+ 'selector': "#head :link, #head :visited",
+ 'expect': [] /*no matches*/,
+ 'exclude': ["document"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ ":link and :visited pseudo-class selectors, chained, mutually exclusive pseudo-classes match nothing",
+ 'selector': ":link:visited",
+ 'expect': [] /*no matches*/,
+ 'exclude': ["document"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE
+ },
// - :target (Level 3)
- {'name': ":target pseudo-class selector, matching the element referenced by the URL fragment identifier", 'selector': ":target", 'expect': [] /*no matches*/, 'exclude': ["document", "element"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
- {'name': ":target pseudo-class selector, matching the element referenced by the URL fragment identifier", 'selector': ":target", 'expect': ["target"], 'exclude': ["fragment", "detached"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ ":target pseudo-class selector, matching the element referenced by the URL fragment identifier",
+ 'selector': ":target",
+ 'expect': [] /*no matches*/,
+ 'exclude': ["document", "element"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
+ {
+ 'name':
+ ":target pseudo-class selector, matching the element referenced by the URL fragment identifier",
+ 'selector': ":target",
+ 'expect': ["target"],
+ 'exclude': ["fragment", "detached"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// - :lang()
- {'name': ":lang pseudo-class selector, matching inherited language", 'selector': "#pseudo-lang-div1:lang(en)", 'expect': ["pseudo-lang-div1"], 'exclude': ["detached", "fragment"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': ":lang pseudo-class selector, not matching element with no inherited language", 'selector': "#pseudo-lang-div1:lang(en)", 'expect': [] /*no matches*/, 'exclude': ["document", "element"], 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': ":lang pseudo-class selector, matching specified language with exact value", 'selector': "#pseudo-lang-div2:lang(fr)", 'expect': ["pseudo-lang-div2"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': ":lang pseudo-class selector, matching specified language with partial value", 'selector': "#pseudo-lang-div3:lang(en)", 'expect': ["pseudo-lang-div3"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': ":lang pseudo-class selector, not matching incorrect language", 'selector': "#pseudo-lang-div4:lang(es-AR)", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
+ {
+ 'name': ":lang pseudo-class selector, matching inherited language",
+ 'selector': "#pseudo-lang-div1:lang(en)",
+ 'expect': ["pseudo-lang-div1"],
+ 'exclude': ["detached", "fragment"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":lang pseudo-class selector, not matching element with no inherited language",
+ 'selector': "#pseudo-lang-div1:lang(en)",
+ 'expect': [] /*no matches*/,
+ 'exclude': ["document", "element"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ ":lang pseudo-class selector, matching specified language with exact value",
+ 'selector': "#pseudo-lang-div2:lang(fr)",
+ 'expect': ["pseudo-lang-div2"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ ":lang pseudo-class selector, matching specified language with partial value",
+ 'selector': "#pseudo-lang-div3:lang(en)",
+ 'expect': ["pseudo-lang-div3"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': ":lang pseudo-class selector, not matching incorrect language",
+ 'selector': "#pseudo-lang-div4:lang(es-AR)",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
// - :enabled (Level 3)
- {'name': ":enabled pseudo-class selector, matching all enabled form controls", 'selector': "#pseudo-ui :enabled", 'expect': ["pseudo-ui-input1", "pseudo-ui-input2", "pseudo-ui-input3", "pseudo-ui-input4", "pseudo-ui-input5", "pseudo-ui-input6",
- "pseudo-ui-input7", "pseudo-ui-input8", "pseudo-ui-input9", "pseudo-ui-textarea1", "pseudo-ui-button1"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ ":enabled pseudo-class selector, matching all enabled form controls",
+ 'selector': "#pseudo-ui :enabled",
+ 'expect': [
+ "pseudo-ui-input1",
+ "pseudo-ui-input2",
+ "pseudo-ui-input3",
+ "pseudo-ui-input4",
+ "pseudo-ui-input5",
+ "pseudo-ui-input6",
+ "pseudo-ui-input7",
+ "pseudo-ui-input8",
+ "pseudo-ui-input9",
+ "pseudo-ui-textarea1",
+ "pseudo-ui-button1"
+ ],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// - :disabled (Level 3)
- {'name': ":enabled pseudo-class selector, matching all disabled form controls", 'selector': "#pseudo-ui :disabled", 'expect': ["pseudo-ui-input10", "pseudo-ui-input11", "pseudo-ui-input12", "pseudo-ui-input13", "pseudo-ui-input14", "pseudo-ui-input15",
- "pseudo-ui-input16", "pseudo-ui-input17", "pseudo-ui-input18", "pseudo-ui-textarea2", "pseudo-ui-button2"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ ":enabled pseudo-class selector, matching all disabled form controls",
+ 'selector': "#pseudo-ui :disabled",
+ 'expect': [
+ "pseudo-ui-input10",
+ "pseudo-ui-input11",
+ "pseudo-ui-input12",
+ "pseudo-ui-input13",
+ "pseudo-ui-input14",
+ "pseudo-ui-input15",
+ "pseudo-ui-input16",
+ "pseudo-ui-input17",
+ "pseudo-ui-input18",
+ "pseudo-ui-textarea2",
+ "pseudo-ui-button2"
+ ],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// - :checked (Level 3)
- {'name': ":checked pseudo-class selector, matching checked radio buttons and checkboxes", 'selector': "#pseudo-ui :checked", 'expect': ["pseudo-ui-input4", "pseudo-ui-input6", "pseudo-ui-input13", "pseudo-ui-input15"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ ":checked pseudo-class selector, matching checked radio buttons and checkboxes",
+ 'selector': "#pseudo-ui :checked",
+ 'expect': [
+ "pseudo-ui-input4",
+ "pseudo-ui-input6",
+ "pseudo-ui-input13",
+ "pseudo-ui-input15"
+ ],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// - :not(s) (Level 3)
- {'name': ":not pseudo-class selector, matching ", 'selector': "#not>:not(div)", 'expect': ["not-p1", "not-p2", "not-p3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":not pseudo-class selector, matching ", 'selector': "#not * :not(:first-child)", 'expect': ["not-em1", "not-em2", "not-em3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': ":not pseudo-class selector, matching nothing", 'selector': ":not(*)", 'expect': [] /* no matches */, 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
- {'name': ":not pseudo-class selector, matching nothing", 'selector': ":not(*|*)", 'expect': [] /* no matches */, 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
+ {
+ 'name': ":not pseudo-class selector, matching ",
+ 'selector': "#not>:not(div)",
+ 'expect': ["not-p1", "not-p2", "not-p3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': ":not pseudo-class selector, matching ",
+ 'selector': "#not * :not(:first-child)",
+ 'expect': ["not-em1", "not-em2", "not-em3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': ":not pseudo-class selector, matching nothing",
+ 'selector': ":not(*)",
+ 'expect': [] /* no matches */,
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
+ {
+ 'name': ":not pseudo-class selector, matching nothing",
+ 'selector': ":not(*|*)",
+ 'expect': [] /* no matches */,
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
// Pseudo-elements
// - ::first-line
- {'name': ":first-line pseudo-element (one-colon syntax) selector, not matching any elements", 'selector': "#pseudo-element:first-line", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "::first-line pseudo-element (two-colon syntax) selector, not matching any elements", 'selector': "#pseudo-element::first-line", 'expect': [] /*no matches*/, 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
+ {
+ 'name':
+ ":first-line pseudo-element (one-colon syntax) selector, not matching any elements",
+ 'selector': "#pseudo-element:first-line",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "::first-line pseudo-element (two-colon syntax) selector, not matching any elements",
+ 'selector': "#pseudo-element::first-line",
+ 'expect': [] /*no matches*/,
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
// - ::first-letter
- {'name': ":first-letter pseudo-element (one-colon syntax) selector, not matching any elements", 'selector': "#pseudo-element:first-letter", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "::first-letter pseudo-element (two-colon syntax) selector, not matching any elements", 'selector': "#pseudo-element::first-letter", 'expect': [] /*no matches*/, 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
+ {
+ 'name':
+ ":first-letter pseudo-element (one-colon syntax) selector, not matching any elements",
+ 'selector': "#pseudo-element:first-letter",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "::first-letter pseudo-element (two-colon syntax) selector, not matching any elements",
+ 'selector': "#pseudo-element::first-letter",
+ 'expect': [] /*no matches*/,
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
// - ::before
- {'name': ":before pseudo-element (one-colon syntax) selector, not matching any elements", 'selector': "#pseudo-element:before", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "::before pseudo-element (two-colon syntax) selector, not matching any elements", 'selector': "#pseudo-element::before", 'expect': [] /*no matches*/, 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
+ {
+ 'name':
+ ":before pseudo-element (one-colon syntax) selector, not matching any elements",
+ 'selector': "#pseudo-element:before",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "::before pseudo-element (two-colon syntax) selector, not matching any elements",
+ 'selector': "#pseudo-element::before",
+ 'expect': [] /*no matches*/,
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
// - ::after
- {'name': ":after pseudo-element (one-colon syntax) selector, not matching any elements", 'selector': "#pseudo-element:after", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "::after pseudo-element (two-colon syntax) selector, not matching any elements", 'selector': "#pseudo-element::after", 'expect': [] /*no matches*/, 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
+ {
+ 'name':
+ ":after pseudo-element (one-colon syntax) selector, not matching any elements",
+ 'selector': "#pseudo-element:after",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "::after pseudo-element (two-colon syntax) selector, not matching any elements",
+ 'selector': "#pseudo-element::after",
+ 'expect': [] /*no matches*/,
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
// Class Selectors
- {'name': "Class selector, matching element with specified class", 'selector': ".class-p", 'expect': ["class-p1","class-p2", "class-p3"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Class selector, chained, matching only elements with all specified classes", 'selector': "#class .apple.orange.banana", 'expect': ["class-div1", "class-div2", "class-p4", "class-div3", "class-p6", "class-div4"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Class Selector, chained, with type selector", 'selector': "div.apple.banana.orange", 'expect': ["class-div1", "class-div2", "class-div3", "class-div4"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
+ {
+ 'name': "Class selector, matching element with specified class",
+ 'selector': ".class-p",
+ 'expect': ["class-p1", "class-p2", "class-p3"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Class selector, chained, matching only elements with all specified classes",
+ 'selector': "#class .apple.orange.banana",
+ 'expect': [
+ "class-div1",
+ "class-div2",
+ "class-p4",
+ "class-div3",
+ "class-p6",
+ "class-div4"
+ ],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "Class Selector, chained, with type selector",
+ 'selector': "div.apple.banana.orange",
+ 'expect': ["class-div1", "class-div2", "class-div3", "class-div4"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
// Caution: If copying and pasting the folowing non-ASCII classes, ensure unicode normalisation is not performed in the process.
- {'name': "Class selector, matching element with class value using non-ASCII characters", 'selector': ".台北Táiběi", 'expect': ["class-span1"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Class selector, matching multiple elements with class value using non-ASCII characters", 'selector': ".台北", 'expect': ["class-span1","class-span2"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Class selector, chained, matching element with multiple class values using non-ASCII characters", 'selector': ".台北Táiběi.台北", 'expect': ["class-span1"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Class selector, matching element with class with escaped character", 'selector': ".foo\\:bar", 'expect': ["class-span3"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Class selector, matching element with class with escaped character", 'selector': ".test\\.foo\\[5\\]bar", 'expect': ["class-span4"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ "Class selector, matching element with class value using non-ASCII characters",
+ 'selector': ".台北Táiběi",
+ 'expect': ["class-span1"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Class selector, matching multiple elements with class value using non-ASCII characters",
+ 'selector': ".台北",
+ 'expect': ["class-span1", "class-span2"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Class selector, chained, matching element with multiple class values using non-ASCII characters",
+ 'selector': ".台北Táiběi.台北",
+ 'expect': ["class-span1"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Class selector, matching element with class with escaped character",
+ 'selector': ".foo\\:bar",
+ 'expect': ["class-span3"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Class selector, matching element with class with escaped character",
+ 'selector': ".test\\.foo\\[5\\]bar",
+ 'expect': ["class-span4"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
// ID Selectors
- {'name': "ID selector, matching element with specified id", 'selector': "#id #id-div1", 'expect': ["id-div1"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "ID selector, chained, matching element with specified id", 'selector': "#id-div1, #id-div1", 'expect': ["id-div1"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "ID selector, chained, matching element with specified id", 'selector': "#id-div1, #id-div2", 'expect': ["id-div1", "id-div2"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "ID Selector, chained, with type selector", 'selector': "div#id-div1, div#id-div2", 'expect': ["id-div1", "id-div2"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "ID selector, not matching non-existent descendant", 'selector': "#id #none", 'expect': [] /*no matches*/, 'level': 1, 'testType': TEST_QSA_BASELINE},
- {'name': "ID selector, not matching non-existent ancestor", 'selector': "#none #id-div1", 'expect': [] /*no matches*/, 'level': 1, 'testType': TEST_QSA_BASELINE},
- {'name': "ID selector, matching multiple elements with duplicate id", 'selector': "#id-li-duplicate", 'expect': ["id-li-duplicate", "id-li-duplicate", "id-li-duplicate", "id-li-duplicate"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
+ {
+ 'name': "ID selector, matching element with specified id",
+ 'selector': "#id #id-div1",
+ 'expect': ["id-div1"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "ID selector, chained, matching element with specified id",
+ 'selector': "#id-div1, #id-div1",
+ 'expect': ["id-div1"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "ID selector, chained, matching element with specified id",
+ 'selector': "#id-div1, #id-div2",
+ 'expect': ["id-div1", "id-div2"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "ID Selector, chained, with type selector",
+ 'selector': "div#id-div1, div#id-div2",
+ 'expect': ["id-div1", "id-div2"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "ID selector, not matching non-existent descendant",
+ 'selector': "#id #none",
+ 'expect': [] /*no matches*/,
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name': "ID selector, not matching non-existent ancestor",
+ 'selector': "#none #id-div1",
+ 'expect': [] /*no matches*/,
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name': "ID selector, matching multiple elements with duplicate id",
+ 'selector': "#id-li-duplicate",
+ 'expect': [
+ "id-li-duplicate",
+ "id-li-duplicate",
+ "id-li-duplicate",
+ "id-li-duplicate"
+ ],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
// Caution: If copying and pasting the folowing non-ASCII IDs, ensure unicode normalisation is not performed in the process.
- {'name': "ID selector, matching id value using non-ASCII characters", 'selector': "#台北Táiběi", 'expect': ["台北Táiběi"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "ID selector, matching id value using non-ASCII characters", 'selector': "#台北", 'expect': ["台北"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "ID selector, matching id values using non-ASCII characters", 'selector': "#台北Táiběi, #台北", 'expect': ["台北Táiběi", "台北"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
+ {
+ 'name': "ID selector, matching id value using non-ASCII characters",
+ 'selector': "#台北Táiběi",
+ 'expect': ["台北Táiběi"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "ID selector, matching id value using non-ASCII characters",
+ 'selector': "#台北",
+ 'expect': ["台北"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "ID selector, matching id values using non-ASCII characters",
+ 'selector': "#台北Táiběi, #台北",
+ 'expect': ["台北Táiběi", "台北"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
// XXX runMatchesTest() in level2-lib.js can't handle this because obtaining the expected nodes requires escaping characters when generating the selector from 'expect' values
- {'name': "ID selector, matching element with id with escaped character", 'selector': "#\\#foo\\:bar", 'expect': ["#foo:bar"], 'level': 1, 'testType': TEST_QSA_BASELINE},
- {'name': "ID selector, matching element with id with escaped character", 'selector': "#test\\.foo\\[5\\]bar", 'expect': ["test.foo[5]bar"], 'level': 1, 'testType': TEST_QSA_BASELINE},
+ {
+ 'name': "ID selector, matching element with id with escaped character",
+ 'selector': "#\\#foo\\:bar",
+ 'expect': ["#foo:bar"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name': "ID selector, matching element with id with escaped character",
+ 'selector': "#test\\.foo\\[5\\]bar",
+ 'expect': ["test.foo[5]bar"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE
+ },
// Namespaces
// XXX runMatchesTest() in level2-lib.js can't handle these because non-HTML elements don't have a recognised id
- {'name': "Namespace selector, matching element with any namespace", 'selector': "#any-namespace *|div", 'expect': ["any-namespace-div1", "any-namespace-div2", "any-namespace-div3", "any-namespace-div4"], 'level': 3, 'testType': TEST_QSA_BASELINE},
- {'name': "Namespace selector, matching div elements in no namespace only", 'selector': "#no-namespace |div", 'expect': ["no-namespace-div3"], 'level': 3, 'testType': TEST_QSA_BASELINE},
- {'name': "Namespace selector, matching any elements in no namespace only", 'selector': "#no-namespace |*", 'expect': ["no-namespace-div3"], 'level': 3, 'testType': TEST_QSA_BASELINE},
+ {
+ 'name': "Namespace selector, matching element with any namespace",
+ 'selector': "#any-namespace *|div",
+ 'expect': [
+ "any-namespace-div1",
+ "any-namespace-div2",
+ "any-namespace-div3",
+ "any-namespace-div4"
+ ],
+ 'level': 3,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name': "Namespace selector, matching div elements in no namespace only",
+ 'selector': "#no-namespace |div",
+ 'expect': ["no-namespace-div3"],
+ 'level': 3,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name': "Namespace selector, matching any elements in no namespace only",
+ 'selector': "#no-namespace |*",
+ 'expect': ["no-namespace-div3"],
+ 'level': 3,
+ 'testType': TEST_QSA_BASELINE
+ },
// Combinators
// - Descendant combinator ' '
- {'name': "Descendant combinator, matching element that is a descendant of an element with id", 'selector': "#descendant div", 'expect': ["descendant-div1", "descendant-div2", "descendant-div3", "descendant-div4"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Descendant combinator, matching element with id that is a descendant of an element", 'selector': "body #descendant-div1", 'expect': ["descendant-div1"], 'exclude': ["detached", "fragment"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Descendant combinator, matching element with id that is a descendant of an element", 'selector': "div #descendant-div1", 'expect': ["descendant-div1"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Descendant combinator, matching element with id that is a descendant of an element with id", 'selector': "#descendant #descendant-div2", 'expect': ["descendant-div2"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Descendant combinator, matching element with class that is a descendant of an element with id", 'selector': "#descendant .descendant-div2", 'expect': ["descendant-div2"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Descendant combinator, matching element with class that is a descendant of an element with class", 'selector': ".descendant-div1 .descendant-div3", 'expect': ["descendant-div3"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Descendant combinator, not matching element with id that is not a descendant of an element with id", 'selector': "#descendant-div1 #descendant-div4", 'expect': [] /*no matches*/, 'level': 1, 'testType': TEST_QSA_BASELINE},
- {'name': "Descendant combinator, whitespace characters", 'selector': "#descendant\t\r\n#descendant-div2", 'expect': ["descendant-div2"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ "Descendant combinator, matching element that is a descendant of an element with id",
+ 'selector': "#descendant div",
+ 'expect': [
+ "descendant-div1",
+ "descendant-div2",
+ "descendant-div3",
+ "descendant-div4"
+ ],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Descendant combinator, matching element with id that is a descendant of an element",
+ 'selector': "body #descendant-div1",
+ 'expect': ["descendant-div1"],
+ 'exclude': ["detached", "fragment"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Descendant combinator, matching element with id that is a descendant of an element",
+ 'selector': "div #descendant-div1",
+ 'expect': ["descendant-div1"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Descendant combinator, matching element with id that is a descendant of an element with id",
+ 'selector': "#descendant #descendant-div2",
+ 'expect': ["descendant-div2"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Descendant combinator, matching element with class that is a descendant of an element with id",
+ 'selector': "#descendant .descendant-div2",
+ 'expect': ["descendant-div2"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Descendant combinator, matching element with class that is a descendant of an element with class",
+ 'selector': ".descendant-div1 .descendant-div3",
+ 'expect': ["descendant-div3"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Descendant combinator, not matching element with id that is not a descendant of an element with id",
+ 'selector': "#descendant-div1 #descendant-div4",
+ 'expect': [] /*no matches*/,
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name': "Descendant combinator, whitespace characters",
+ 'selector': "#descendant\t\r\n#descendant-div2",
+ 'expect': ["descendant-div2"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
// - Child combinator '>'
- {'name': "Child combinator, matching element that is a child of an element with id", 'selector': "#child>div", 'expect': ["child-div1", "child-div4"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Child combinator, matching element with id that is a child of an element", 'selector': "div>#child-div1", 'expect': ["child-div1"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Child combinator, matching element with id that is a child of an element with id", 'selector': "#child>#child-div1", 'expect': ["child-div1"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Child combinator, matching element with id that is a child of an element with class", 'selector': "#child-div1>.child-div2", 'expect': ["child-div2"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Child combinator, matching element with class that is a child of an element with class", 'selector': ".child-div1>.child-div2", 'expect': ["child-div2"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Child combinator, not matching element with id that is not a child of an element with id", 'selector': "#child>#child-div3", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "Child combinator, not matching element with id that is not a child of an element with class", 'selector': "#child-div1>.child-div3", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "Child combinator, not matching element with class that is not a child of an element with class", 'selector': ".child-div1>.child-div3", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "Child combinator, surrounded by whitespace", 'selector': "#child-div1\t\r\n>\t\r\n#child-div2", 'expect': ["child-div2"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Child combinator, whitespace after", 'selector': "#child-div1>\t\r\n#child-div2", 'expect': ["child-div2"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Child combinator, whitespace before", 'selector': "#child-div1\t\r\n>#child-div2", 'expect': ["child-div2"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Child combinator, no whitespace", 'selector': "#child-div1>#child-div2", 'expect': ["child-div2"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ "Child combinator, matching element that is a child of an element with id",
+ 'selector': "#child>div",
+ 'expect': ["child-div1", "child-div4"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Child combinator, matching element with id that is a child of an element",
+ 'selector': "div>#child-div1",
+ 'expect': ["child-div1"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Child combinator, matching element with id that is a child of an element with id",
+ 'selector': "#child>#child-div1",
+ 'expect': ["child-div1"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Child combinator, matching element with id that is a child of an element with class",
+ 'selector': "#child-div1>.child-div2",
+ 'expect': ["child-div2"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Child combinator, matching element with class that is a child of an element with class",
+ 'selector': ".child-div1>.child-div2",
+ 'expect': ["child-div2"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Child combinator, not matching element with id that is not a child of an element with id",
+ 'selector': "#child>#child-div3",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "Child combinator, not matching element with id that is not a child of an element with class",
+ 'selector': "#child-div1>.child-div3",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name':
+ "Child combinator, not matching element with class that is not a child of an element with class",
+ 'selector': ".child-div1>.child-div3",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name': "Child combinator, surrounded by whitespace",
+ 'selector': "#child-div1\t\r\n>\t\r\n#child-div2",
+ 'expect': ["child-div2"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "Child combinator, whitespace after",
+ 'selector': "#child-div1>\t\r\n#child-div2",
+ 'expect': ["child-div2"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "Child combinator, whitespace before",
+ 'selector': "#child-div1\t\r\n>#child-div2",
+ 'expect': ["child-div2"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "Child combinator, no whitespace",
+ 'selector': "#child-div1>#child-div2",
+ 'expect': ["child-div2"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
// - Adjacent sibling combinator '+'
- {'name': "Adjacent sibling combinator, matching element that is an adjacent sibling of an element with id", 'selector': "#adjacent-div2+div", 'expect': ["adjacent-div4"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element", 'selector': "div+#adjacent-div4", 'expect': ["adjacent-div4"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element with id", 'selector': "#adjacent-div2+#adjacent-div4", 'expect': ["adjacent-div4"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with id", 'selector': "#adjacent-div2+.adjacent-div4", 'expect': ["adjacent-div4"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with class", 'selector': ".adjacent-div2+.adjacent-div4", 'expect': ["adjacent-div4"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Adjacent sibling combinator, matching p element that is an adjacent sibling of a div element", 'selector': "#adjacent div+p", 'expect': ["adjacent-p2"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Adjacent sibling combinator, not matching element with id that is not an adjacent sibling of an element with id", 'selector': "#adjacent-div2+#adjacent-p2, #adjacent-div2+#adjacent-div1", 'expect': [] /*no matches*/, 'level': 2, 'testType': TEST_QSA_BASELINE},
- {'name': "Adjacent sibling combinator, surrounded by whitespace", 'selector': "#adjacent-p2\t\r\n+\t\r\n#adjacent-p3", 'expect': ["adjacent-p3"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Adjacent sibling combinator, whitespace after", 'selector': "#adjacent-p2+\t\r\n#adjacent-p3", 'expect': ["adjacent-p3"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Adjacent sibling combinator, whitespace before", 'selector': "#adjacent-p2\t\r\n+#adjacent-p3", 'expect': ["adjacent-p3"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Adjacent sibling combinator, no whitespace", 'selector': "#adjacent-p2+#adjacent-p3", 'expect': ["adjacent-p3"], 'level': 2, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ "Adjacent sibling combinator, matching element that is an adjacent sibling of an element with id",
+ 'selector': "#adjacent-div2+div",
+ 'expect': ["adjacent-div4"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element",
+ 'selector': "div+#adjacent-div4",
+ 'expect': ["adjacent-div4"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element with id",
+ 'selector': "#adjacent-div2+#adjacent-div4",
+ 'expect': ["adjacent-div4"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with id",
+ 'selector': "#adjacent-div2+.adjacent-div4",
+ 'expect': ["adjacent-div4"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with class",
+ 'selector': ".adjacent-div2+.adjacent-div4",
+ 'expect': ["adjacent-div4"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Adjacent sibling combinator, matching p element that is an adjacent sibling of a div element",
+ 'selector': "#adjacent div+p",
+ 'expect': ["adjacent-p2"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "Adjacent sibling combinator, not matching element with id that is not an adjacent sibling of an element with id",
+ 'selector': "#adjacent-div2+#adjacent-p2, #adjacent-div2+#adjacent-div1",
+ 'expect': [] /*no matches*/,
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE
+ },
+ {
+ 'name': "Adjacent sibling combinator, surrounded by whitespace",
+ 'selector': "#adjacent-p2\t\r\n+\t\r\n#adjacent-p3",
+ 'expect': ["adjacent-p3"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "Adjacent sibling combinator, whitespace after",
+ 'selector': "#adjacent-p2+\t\r\n#adjacent-p3",
+ 'expect': ["adjacent-p3"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "Adjacent sibling combinator, whitespace before",
+ 'selector': "#adjacent-p2\t\r\n+#adjacent-p3",
+ 'expect': ["adjacent-p3"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "Adjacent sibling combinator, no whitespace",
+ 'selector': "#adjacent-p2+#adjacent-p3",
+ 'expect': ["adjacent-p3"],
+ 'level': 2,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
// - General sibling combinator ~ (Level 3)
- {'name': "General sibling combinator, matching element that is a sibling of an element with id", 'selector': "#sibling-div2~div", 'expect': ["sibling-div4", "sibling-div6"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "General sibling combinator, matching element with id that is a sibling of an element", 'selector': "div~#sibling-div4", 'expect': ["sibling-div4"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "General sibling combinator, matching element with id that is a sibling of an element with id", 'selector': "#sibling-div2~#sibling-div4", 'expect': ["sibling-div4"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "General sibling combinator, matching element with class that is a sibling of an element with id", 'selector': "#sibling-div2~.sibling-div", 'expect': ["sibling-div4", "sibling-div6"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "General sibling combinator, matching p element that is a sibling of a div element", 'selector': "#sibling div~p", 'expect': ["sibling-p2", "sibling-p3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "General sibling combinator, not matching element with id that is not a sibling after a p element", 'selector': "#sibling>p~div", 'expect': [] /*no matches*/, 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
- {'name': "General sibling combinator, not matching element with id that is not a sibling after an element with id", 'selector': "#sibling-div2~#sibling-div3, #sibling-div2~#sibling-div1", 'expect': [] /*no matches*/, 'level': 3, 'testType': TEST_QSA_ADDITIONAL},
- {'name': "General sibling combinator, surrounded by whitespace", 'selector': "#sibling-p2\t\r\n~\t\r\n#sibling-p3", 'expect': ["sibling-p3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "General sibling combinator, whitespace after", 'selector': "#sibling-p2~\t\r\n#sibling-p3", 'expect': ["sibling-p3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "General sibling combinator, whitespace before", 'selector': "#sibling-p2\t\r\n~#sibling-p3", 'expect': ["sibling-p3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
- {'name': "General sibling combinator, no whitespace", 'selector': "#sibling-p2~#sibling-p3", 'expect': ["sibling-p3"], 'level': 3, 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE},
+ {
+ 'name':
+ "General sibling combinator, matching element that is a sibling of an element with id",
+ 'selector': "#sibling-div2~div",
+ 'expect': ["sibling-div4", "sibling-div6"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "General sibling combinator, matching element with id that is a sibling of an element",
+ 'selector': "div~#sibling-div4",
+ 'expect': ["sibling-div4"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "General sibling combinator, matching element with id that is a sibling of an element with id",
+ 'selector': "#sibling-div2~#sibling-div4",
+ 'expect': ["sibling-div4"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "General sibling combinator, matching element with class that is a sibling of an element with id",
+ 'selector': "#sibling-div2~.sibling-div",
+ 'expect': ["sibling-div4", "sibling-div6"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "General sibling combinator, matching p element that is a sibling of a div element",
+ 'selector': "#sibling div~p",
+ 'expect': ["sibling-p2", "sibling-p3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name':
+ "General sibling combinator, not matching element with id that is not a sibling after a p element",
+ 'selector': "#sibling>p~div",
+ 'expect': [] /*no matches*/,
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
+ {
+ 'name':
+ "General sibling combinator, not matching element with id that is not a sibling after an element with id",
+ 'selector': "#sibling-div2~#sibling-div3, #sibling-div2~#sibling-div1",
+ 'expect': [] /*no matches*/,
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL
+ },
+ {
+ 'name': "General sibling combinator, surrounded by whitespace",
+ 'selector': "#sibling-p2\t\r\n~\t\r\n#sibling-p3",
+ 'expect': ["sibling-p3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "General sibling combinator, whitespace after",
+ 'selector': "#sibling-p2~\t\r\n#sibling-p3",
+ 'expect': ["sibling-p3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "General sibling combinator, whitespace before",
+ 'selector': "#sibling-p2\t\r\n~#sibling-p3",
+ 'expect': ["sibling-p3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "General sibling combinator, no whitespace",
+ 'selector': "#sibling-p2~#sibling-p3",
+ 'expect': ["sibling-p3"],
+ 'level': 3,
+ 'testType': TEST_QSA_ADDITIONAL | TEST_MATCH_BASELINE
+ },
// Group of selectors (comma)
- {'name': "Syntax, group of selectors separator, surrounded by whitespace", 'selector': "#group em\t\r \n,\t\r \n#group strong", 'expect': ["group-em1", "group-strong1"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Syntax, group of selectors separator, whitespace after", 'selector': "#group em,\t\r\n#group strong", 'expect': ["group-em1", "group-strong1"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Syntax, group of selectors separator, whitespace before", 'selector': "#group em\t\r\n,#group strong", 'expect': ["group-em1", "group-strong1"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
- {'name': "Syntax, group of selectors separator, no whitespace", 'selector': "#group em,#group strong", 'expect': ["group-em1", "group-strong1"], 'level': 1, 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE},
+ {
+ 'name': "Syntax, group of selectors separator, surrounded by whitespace",
+ 'selector': "#group em\t\r \n,\t\r \n#group strong",
+ 'expect': ["group-em1", "group-strong1"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "Syntax, group of selectors separator, whitespace after",
+ 'selector': "#group em,\t\r\n#group strong",
+ 'expect': ["group-em1", "group-strong1"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "Syntax, group of selectors separator, whitespace before",
+ 'selector': "#group em\t\r\n,#group strong",
+ 'expect': ["group-em1", "group-strong1"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
+ {
+ 'name': "Syntax, group of selectors separator, no whitespace",
+ 'selector': "#group em,#group strong",
+ 'expect': ["group-em1", "group-strong1"],
+ 'level': 1,
+ 'testType': TEST_QSA_BASELINE | TEST_MATCH_BASELINE
+ },
];
diff --git a/test/support.dart b/test/support.dart
index 0118ecf..d8f66b1 100644
--- a/test/support.dart
+++ b/test/support.dart
@@ -14,7 +14,7 @@
Map<String, TreeBuilderFactory> get treeTypes {
if (_treeTypes == null) {
// TODO(jmesserly): add DOM here once it's implemented
- _treeTypes = { "simpletree": (useNs) => new TreeBuilder(useNs) };
+ _treeTypes = {"simpletree": (useNs) => new TreeBuilder(useNs)};
}
return _treeTypes;
}
@@ -45,7 +45,6 @@
var key = null;
var result = <Map>[];
var lines = _text.split('\n');
- int numLines = lines.length;
// Remove trailing newline to match Python
if (lines.last == '') {
lines.removeLast();
diff --git a/test/tokenizer_test.dart b/test/tokenizer_test.dart
index 5c87e16..6b6a1ea 100644
--- a/test/tokenizer_test.dart
+++ b/test/tokenizer_test.dart
@@ -30,8 +30,7 @@
// Note: we can't get a closure of the state method. However, we can
// create a new closure to invoke it via mirrors.
var mtok = reflect(tokenizer);
- tokenizer.state = () =>
- mtok.invoke(new Symbol(_state), const []).reflectee;
+ tokenizer.state = () => mtok.invoke(new Symbol(_state), const []).reflectee;
if (_lastStartTag != null) {
tokenizer.currentToken = new StartTagToken(_lastStartTag);
@@ -68,8 +67,8 @@
}
void processDoctype(DoctypeToken token) {
- outputTokens.add(["DOCTYPE", token.name, token.publicId,
- token.systemId, token.correct]);
+ outputTokens.add(
+ ["DOCTYPE", token.name, token.publicId, token.systemId, token.correct]);
}
void processStartTag(StartTagToken token) {
@@ -92,8 +91,7 @@
outputTokens.add(["Character", token.data]);
}
- void processEOF(token) {
- }
+ void processEOF(token) {}
void processParseError(StringToken token) {
// TODO(jmesserly): when debugging test failures it can be useful to add
@@ -110,7 +108,6 @@
if (outputTokens.length > 0 &&
outputTokens.last.indexOf("ParseError") == -1 &&
outputTokens.last[0] == "Character") {
-
outputTokens.last[1] = '${outputTokens.last[1]}${token[1]}';
} else {
outputTokens.add(token);
@@ -133,18 +130,17 @@
return tokens;
}
-
/// Test whether the test has passed or failed
///
/// If the ignoreErrorOrder flag is set to true we don't test the relative
/// positions of parse errors and non parse errors.
-void expectTokensMatch(List expectedTokens, List receivedTokens,
- bool ignoreErrorOrder, [bool ignoreErrors = false, String message]) {
-
+void expectTokensMatch(
+ List expectedTokens, List receivedTokens, bool ignoreErrorOrder,
+ [bool ignoreErrors = false, String message]) {
var checkSelfClosing = false;
for (var token in expectedTokens) {
- if (token[0] == "StartTag" && token.length == 4
- || token[0] == "EndTag" && token.length == 3) {
+ if (token[0] == "StartTag" && token.length == 4 ||
+ token[0] == "EndTag" && token.length == 3) {
checkSelfClosing = true;
break;
}
@@ -185,16 +181,21 @@
if (!testInfo.containsKey('lastStartTag')) {
testInfo['lastStartTag'] = null;
}
- var parser = new TokenizerTestParser(testInfo['initialState'],
- testInfo['lastStartTag']);
+ var parser = new TokenizerTestParser(
+ testInfo['initialState'], testInfo['lastStartTag']);
var tokens = parser.parse(testInfo['input']);
tokens = concatenateCharacterTokens(tokens);
var received = normalizeTokens(tokens);
- var errorMsg = ["\n\nInitial state:",
- testInfo['initialState'],
- "\nInput:", testInfo['input'],
- "\nExpected:", expected,
- "\nreceived:", tokens].map((s) => '$s').join('\n');
+ var errorMsg = [
+ "\n\nInitial state:",
+ testInfo['initialState'],
+ "\nInput:",
+ testInfo['input'],
+ "\nExpected:",
+ expected,
+ "\nreceived:",
+ tokens
+ ].map((s) => '$s').join('\n');
var ignoreErrorOrder = testInfo['ignoreErrorOrder'];
if (ignoreErrorOrder == null) ignoreErrorOrder = false;
@@ -226,7 +227,6 @@
return testInfo;
}
-
String camelCase(String s) {
s = s.toLowerCase();
var result = new StringBuffer();