Make package:html strong clean R=jmesserly@google.com Review URL: https://codereview.chromium.org//1971923002 .
diff --git a/.analysis_options b/.analysis_options new file mode 100644 index 0000000..a10d4c5 --- /dev/null +++ b/.analysis_options
@@ -0,0 +1,2 @@ +analyzer: + strong-mode: true
diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dbea39..3320989 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md
@@ -3,6 +3,14 @@ This file contains highlights of what changes on each version of the html package. +## 0.13.0 + + * **BREAKING** Fix all [strong mode][] errors and warnings. + This involved adding more precise types on some public APIs, which is why it + may break users. + +[strong mode]: https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md + #### Pub version 0.12.2+2 * Support `csslib` versions `0.13.x`.
diff --git a/lib/dom.dart b/lib/dom.dart index 9e64759..63182f6 100644 --- a/lib/dom.dart +++ b/lib/dom.dart
@@ -742,16 +742,17 @@ // 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, + void setRange(int start, int rangeLength, Iterable<Node> from, [int startFrom = 0]) { - if (from is NodeList) { + List<Node> from_ = from as List<Node>; + if (from_ is NodeList) { // Note: this is presumed to make a copy - from = from.sublist(startFrom, startFrom + rangeLength); + from_ = from_.sublist(startFrom, startFrom + rangeLength); } // Note: see comment in [addAll]. We need to be careful about the order of // operations if [from] is also a NodeList. for (int i = rangeLength - 1; i >= 0; i--) { - this[start + i] = from[startFrom + i]; + this[start + i] = from_[startFrom + i]; } } @@ -765,14 +766,14 @@ super.removeRange(start, rangeLength); } - void removeWhere(bool test(Element e)) { + void removeWhere(bool test(Node e)) { for (var node in where(test)) { node.parentNode = null; } super.removeWhere(test); } - void retainWhere(bool test(Element e)) { + void retainWhere(bool test(Node e)) { for (var node in where((n) => !test(n))) { node.parentNode = null; } @@ -786,11 +787,11 @@ super.insertAll(index, list); } - _flattenDocFragments(Iterable<Node> collection) { + List<Node> _flattenDocFragments(Iterable<Node> collection) { // Note: this function serves two purposes: // * it flattens document fragments // * it creates a copy of [collections] when `collection is NodeList`. - var result = []; + var result = <Node>[]; for (var node in collection) { if (node is DocumentFragment) { result.addAll(node.nodes); @@ -860,7 +861,7 @@ } } - bool contains(Element element) { + bool contains(Object element) { return element is Element && _childNodes.contains(element); } @@ -901,9 +902,10 @@ return result; } - Iterable map(f(Element element)) => _filtered.map(f); + Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(Element element)) => _filtered.map(f); Iterable<Element> where(bool f(Element element)) => _filtered.where(f); - Iterable expand(Iterable f(Element element)) => _filtered.expand(f); + Iterable/*<T>*/ expand/*<T>*/(Iterable/*<T>*/ f(Element element)) => + _filtered.expand(f); void insert(int index, Element value) { _childNodes.insert(index, value); @@ -935,8 +937,8 @@ return _filtered.reduce(combine); } - dynamic fold(dynamic initialValue, - dynamic combine(dynamic previousValue, Element element)) { + dynamic/*=T*/ fold/*<T>*/(var/*=T*/ initialValue, + dynamic/*=T*/ combine(var/*=T*/ previousValue, Element element)) { return _filtered.fold(initialValue, combine); } @@ -968,10 +970,14 @@ List<Element> sublist(int start, [int end]) => _filtered.sublist(start, end); Iterable<Element> getRange(int start, int end) => _filtered.getRange(start, end); - int indexOf(Element element, [int start = 0]) => + // TODO(sigmund): this should be typed Element, but we currently run into a + // bug where ListMixin<E>.indexOf() expects Object as the argument. + int indexOf(element, [int start = 0]) => _filtered.indexOf(element, start); - int lastIndexOf(Element element, [int start = null]) { + // TODO(sigmund): this should be typed Element, but we currently run into a + // bug where ListMixin<E>.lastIndexOf() expects Object as the argument. + int lastIndexOf(element, [int start = null]) { if (start == null) start = length - 1; return _filtered.lastIndexOf(element, start); }
diff --git a/lib/parser.dart b/lib/parser.dart index dc95941..0575b3d 100644 --- a/lib/parser.dart +++ b/lib/parser.dart
@@ -210,7 +210,7 @@ try { mainLoop(); break; - } on ReparseException catch (e) { + } on ReparseException catch (_) { // Note: this happens if we start parsing but the character encoding // changes. So we should only need to restart very early in the parse. reset(); @@ -819,7 +819,8 @@ // helper methods void insertHtmlElement() { - tree.insertRoot(new StartTagToken("html", data: {})); + tree.insertRoot(new StartTagToken("html", + data: new LinkedHashMap<dynamic, String>())); parser.phase = parser._beforeHeadPhase; } @@ -875,7 +876,8 @@ case 'html': return startTagHtml(token); case 'head': - return startTagHead(token); + startTagHead(token); + return null; default: return startTagOther(token); } @@ -889,12 +891,14 @@ case "br": return endTagImplyHead(token); default: - return endTagOther(token); + endTagOther(token); + return null; } } bool processEOF() { - startTagHead(new StartTagToken("head", data: {})); + startTagHead(new StartTagToken("head", + data: new LinkedHashMap<dynamic, String>())); return true; } @@ -903,7 +907,8 @@ } Token processCharacters(CharactersToken token) { - startTagHead(new StartTagToken("head", data: {})); + startTagHead(new StartTagToken("head", + data: new LinkedHashMap<dynamic, String>())); return token; } @@ -918,12 +923,14 @@ } Token startTagOther(StartTagToken token) { - startTagHead(new StartTagToken("head", data: {})); + startTagHead(new StartTagToken("head", + data: new LinkedHashMap<dynamic, String>())); return token; } Token endTagImplyHead(EndTagToken token) { - startTagHead(new StartTagToken("head", data: {})); + startTagHead(new StartTagToken("head", + data: new LinkedHashMap<dynamic, String>())); return token; } @@ -941,23 +948,29 @@ case "html": return startTagHtml(token); case "title": - return startTagTitle(token); + startTagTitle(token); + return null; case "noscript": case "noframes": case "style": - return startTagNoScriptNoFramesStyle(token); + startTagNoScriptNoFramesStyle(token); + return null; case "script": - return startTagScript(token); + startTagScript(token); + return null; case "base": case "basefont": case "bgsound": case "command": case "link": - return startTagBaseLinkCommand(token); + startTagBaseLinkCommand(token); + return null; case "meta": - return startTagMeta(token); + startTagMeta(token); + return null; case "head": - return startTagHead(token); + startTagHead(token); + return null; default: return startTagOther(token); } @@ -966,13 +979,15 @@ processEndTag(EndTagToken token) { switch (token.name) { case "head": - return endTagHead(token); + endTagHead(token); + return null; case "br": case "html": case "body": return endTagHtmlBodyBr(token); default: - return endTagOther(token); + endTagOther(token); + return null; } } @@ -1075,9 +1090,11 @@ case "html": return startTagHtml(token); case "body": - return startTagBody(token); + startTagBody(token); + return null; case "frameset": - return startTagFrameset(token); + startTagFrameset(token); + return null; case "base": case "basefont": case "bgsound": @@ -1087,9 +1104,11 @@ case "script": case "style": case "title": - return startTagFromHead(token); + startTagFromHead(token); + return null; case "head": - return startTagHead(token); + startTagHead(token); + return null; default: return startTagOther(token); } @@ -1102,7 +1121,8 @@ case "br": return endTagHtmlBodyBr(token); default: - return endTagOther(token); + endTagOther(token); + return null; } } @@ -1164,7 +1184,8 @@ } void anythingElse() { - tree.insertElement(new StartTagToken("body", data: {})); + tree.insertElement(new StartTagToken("body", + data: new LinkedHashMap<dynamic, String>())); parser.phase = parser._inBodyPhase; parser.framesetOK = true; } @@ -1195,9 +1216,11 @@ case "title": return startTagProcessInHead(token); case "body": - return startTagBody(token); + startTagBody(token); + return null; case "frameset": - return startTagFrameset(token); + startTagFrameset(token); + return null; case "address": case "article": case "aside": @@ -1221,7 +1244,8 @@ case "section": case "summary": case "ul": - return startTagCloseP(token); + startTagCloseP(token); + return null; // headingElements case "h1": case "h2": @@ -1229,20 +1253,26 @@ case "h4": case "h5": case "h6": - return startTagHeading(token); + startTagHeading(token); + return null; case "pre": case "listing": - return startTagPreListing(token); + startTagPreListing(token); + return null; case "form": - return startTagForm(token); + startTagForm(token); + return null; case "li": case "dd": case "dt": - return startTagListItem(token); + startTagListItem(token); + return null; case "plaintext": - return startTagPlaintext(token); + startTagPlaintext(token); + return null; case "a": - return startTagA(token); + startTagA(token); + return null; case "b": case "big": case "code": @@ -1255,58 +1285,77 @@ case "strong": case "tt": case "u": - return startTagFormatting(token); + startTagFormatting(token); + return null; case "nobr": - return startTagNobr(token); + startTagNobr(token); + return null; case "button": return startTagButton(token); case "applet": case "marquee": case "object": - return startTagAppletMarqueeObject(token); + startTagAppletMarqueeObject(token); + return null; case "xmp": - return startTagXmp(token); + startTagXmp(token); + return null; case "table": - return startTagTable(token); + startTagTable(token); + return null; case "area": case "br": case "embed": case "img": case "keygen": case "wbr": - return startTagVoidFormatting(token); + startTagVoidFormatting(token); + return null; case "param": case "source": case "track": - return startTagParamSource(token); + startTagParamSource(token); + return null; case "input": - return startTagInput(token); + startTagInput(token); + return null; case "hr": - return startTagHr(token); + startTagHr(token); + return null; case "image": - return startTagImage(token); + startTagImage(token); + return null; case "isindex": - return startTagIsIndex(token); + startTagIsIndex(token); + return null; case "textarea": - return startTagTextarea(token); + startTagTextarea(token); + return null; case "iframe": - return startTagIFrame(token); + startTagIFrame(token); + return null; case "noembed": case "noframes": case "noscript": - return startTagRawtext(token); + startTagRawtext(token); + return null; case "select": - return startTagSelect(token); + startTagSelect(token); + return null; case "rp": case "rt": - return startTagRpRt(token); + startTagRpRt(token); + return null; case "option": case "optgroup": - return startTagOpt(token); + startTagOpt(token); + return null; case "math": - return startTagMath(token); + startTagMath(token); + return null; case "svg": - return startTagSvg(token); + startTagSvg(token); + return null; case "caption": case "col": case "colgroup": @@ -1318,7 +1367,8 @@ case "th": case "thead": case "tr": - return startTagMisplaced(token); + startTagMisplaced(token); + return null; default: return startTagOther(token); } @@ -1327,7 +1377,8 @@ processEndTag(EndTagToken token) { switch (token.name) { case "body": - return endTagBody(token); + endTagBody(token); + return null; case "html": return endTagHtml(token); case "address": @@ -1353,15 +1404,19 @@ case "section": case "summary": case "ul": - return endTagBlock(token); + endTagBlock(token); + return null; case "form": - return endTagForm(token); + endTagForm(token); + return null; case "p": - return endTagP(token); + endTagP(token); + return null; case "dd": case "dt": case "li": - return endTagListItem(token); + endTagListItem(token); + return null; // headingElements case "h1": case "h2": @@ -1369,7 +1424,8 @@ case "h4": case "h5": case "h6": - return endTagHeading(token); + endTagHeading(token); + return null; case "a": case "b": case "big": @@ -1384,15 +1440,19 @@ case "strong": case "tt": case "u": - return endTagFormatting(token); + endTagFormatting(token); + return null; case "applet": case "marquee": case "object": - return endTagAppletMarqueeObject(token); + endTagAppletMarqueeObject(token); + return null; case "br": - return endTagBr(token); + endTagBr(token); + return null; default: - return endTagOther(token); + endTagOther(token); + return null; } } @@ -1733,28 +1793,31 @@ if (tree.formPointer != null) { return; } - var formAttrs = {}; + var formAttrs = new LinkedHashMap<dynamic, String>(); var dataAction = token.data["action"]; if (dataAction != null) { formAttrs["action"] = dataAction; } processStartTag(new StartTagToken("form", data: formAttrs)); - processStartTag(new StartTagToken("hr", data: {})); - processStartTag(new StartTagToken("label", data: {})); + processStartTag(new StartTagToken("hr", + data: new LinkedHashMap<dynamic, String>())); + processStartTag(new StartTagToken("label", + data: new LinkedHashMap<dynamic, String>())); // XXX Localization ... var prompt = token.data["prompt"]; if (prompt == null) { prompt = "This is a searchable index. Enter search keywords: "; } processCharacters(new CharactersToken(prompt)); - var attributes = new LinkedHashMap.from(token.data); + var attributes = new LinkedHashMap<dynamic, String>.from(token.data); attributes.remove('action'); attributes.remove('prompt'); attributes["name"] = "isindex"; processStartTag(new StartTagToken( "input", data: attributes, selfClosing: token.selfClosing)); processEndTag(new EndTagToken("label")); - processStartTag(new StartTagToken("hr", data: {})); + processStartTag(new StartTagToken("hr", + data: new LinkedHashMap<dynamic, String>())); processEndTag(new EndTagToken("form")); } @@ -1857,7 +1920,8 @@ void endTagP(EndTagToken token) { if (!tree.elementInScope("p", variant: "button")) { - startTagCloseP(new StartTagToken("p", data: {})); + startTagCloseP(new StartTagToken("p", + data: new LinkedHashMap<dynamic, String>())); parser.parseError(token.span, "unexpected-end-tag", {"name": "p"}); endTagP(new EndTagToken("p")); } else { @@ -1994,7 +2058,7 @@ } /// The much-feared adoption agency algorithm. - endTagFormatting(EndTagToken token) { + void endTagFormatting(EndTagToken token) { // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#adoptionAgency // TODO(jmesserly): the comments here don't match the numbered steps in the // updated spec. This needs a pass over it to verify that it still matches. @@ -2164,7 +2228,8 @@ "newName": "br element" }); tree.reconstructActiveFormattingElements(); - tree.insertElement(new StartTagToken("br", data: {})); + tree.insertElement(new StartTagToken("br", + data: new LinkedHashMap<dynamic, String>())); tree.openElements.removeLast(); } @@ -2199,8 +2264,11 @@ } processEndTag(EndTagToken token) { - if (token.name == 'script') return endTagScript(token); - return endTagOther(token); + if (token.name == 'script') { + endTagScript(token); + return null; + } + endTagOther(token); } Token processCharacters(CharactersToken token) { @@ -2240,15 +2308,18 @@ case "html": return startTagHtml(token); case "caption": - return startTagCaption(token); + startTagCaption(token); + return null; case "colgroup": - return startTagColgroup(token); + startTagColgroup(token); + return null; case "col": return startTagCol(token); case "tbody": case "tfoot": case "thead": - return startTagRowGroup(token); + startTagRowGroup(token); + return null; case "td": case "th": case "tr": @@ -2259,18 +2330,22 @@ case "script": return startTagStyleScript(token); case "input": - return startTagInput(token); + startTagInput(token); + return null; case "form": - return startTagForm(token); + startTagForm(token); + return null; default: - return startTagOther(token); + startTagOther(token); + return null; } } processEndTag(EndTagToken token) { switch (token.name) { case "table": - return endTagTable(token); + endTagTable(token); + return null; case "body": case "caption": case "col": @@ -2282,9 +2357,11 @@ case "th": case "thead": case "tr": - return endTagIgnore(token); + endTagIgnore(token); + return null; default: - return endTagOther(token); + endTagOther(token); + return null; } } @@ -2350,7 +2427,8 @@ } Token startTagCol(StartTagToken token) { - startTagColgroup(new StartTagToken("colgroup", data: {})); + startTagColgroup(new StartTagToken("colgroup", + data: new LinkedHashMap<dynamic, String>())); return token; } @@ -2361,7 +2439,8 @@ } Token startTagImplyTbody(StartTagToken token) { - startTagRowGroup(new StartTagToken("tbody", data: {})); + startTagRowGroup(new StartTagToken("tbody", + data: new LinkedHashMap<dynamic, String>())); return token; } @@ -2542,7 +2621,8 @@ processEndTag(EndTagToken token) { switch (token.name) { case "caption": - return endTagCaption(token); + endTagCaption(token); + return null; case "table": return endTagTable(token); case "body": @@ -2555,7 +2635,8 @@ case "th": case "thead": case "tr": - return endTagIgnore(token); + endTagIgnore(token); + return null; default: return endTagOther(token); } @@ -2641,7 +2722,8 @@ case "html": return startTagHtml(token); case "col": - return startTagCol(token); + startTagCol(token); + return null; default: return startTagOther(token); } @@ -2650,9 +2732,11 @@ processEndTag(EndTagToken token) { switch (token.name) { case "colgroup": - return endTagColgroup(token); + endTagColgroup(token); + return null; case "col": - return endTagCol(token); + endTagCol(token); + return null; default: return endTagOther(token); } @@ -2722,7 +2806,8 @@ case "html": return startTagHtml(token); case "tr": - return startTagTr(token); + startTagTr(token); + return null; case "td": case "th": return startTagTableCell(token); @@ -2743,7 +2828,8 @@ case "tbody": case "tfoot": case "thead": - return endTagTableRowGroup(token); + endTagTableRowGroup(token); + return null; case "table": return endTagTable(token); case "body": @@ -2754,7 +2840,8 @@ case "td": case "th": case "tr": - return endTagIgnore(token); + endTagIgnore(token); + return null; default: return endTagOther(token); } @@ -2796,7 +2883,8 @@ Token startTagTableCell(StartTagToken token) { parser.parseError( token.span, "unexpected-cell-in-table-body", {"name": token.name}); - startTagTr(new StartTagToken("tr", data: {})); + startTagTr(new StartTagToken("tr", + data: new LinkedHashMap<dynamic, String>())); return token; } @@ -2854,7 +2942,8 @@ return startTagHtml(token); case "td": case "th": - return startTagTableCell(token); + startTagTableCell(token); + return null; case "caption": case "col": case "colgroup": @@ -2871,7 +2960,8 @@ processEndTag(EndTagToken token) { switch (token.name) { case "tr": - return endTagTr(token); + endTagTr(token); + return null; case "table": return endTagTable(token); case "tbody": @@ -2885,7 +2975,8 @@ case "html": case "td": case "th": - return endTagIgnore(token); + endTagIgnore(token); + return null; default: return endTagOther(token); } @@ -3009,13 +3100,15 @@ switch (token.name) { case "td": case "th": - return endTagTableCell(token); + endTagTableCell(token); + return null; case "body": case "caption": case "col": case "colgroup": case "html": - return endTagIgnore(token); + endTagIgnore(token); + return null; case "table": case "tbody": case "tfoot": @@ -3109,11 +3202,14 @@ case "html": return startTagHtml(token); case "option": - return startTagOption(token); + startTagOption(token); + return null; case "optgroup": - return startTagOptgroup(token); + startTagOptgroup(token); + return null; case "select": - return startTagSelect(token); + startTagSelect(token); + return null; case "input": case "keygen": case "textarea": @@ -3128,13 +3224,17 @@ processEndTag(EndTagToken token) { switch (token.name) { case "option": - return endTagOption(token); + endTagOption(token); + return null; case "optgroup": - return endTagOptgroup(token); + endTagOptgroup(token); + return null; case "select": - return endTagSelect(token); + endTagSelect(token); + return null; default: - return endTagOther(token); + endTagOther(token); + return null; } } @@ -3504,7 +3604,10 @@ } processEndTag(EndTagToken token) { - if (token.name == "html") return endTagHtml(token); + if (token.name == "html") { + endTagHtml(token); + return null; + } return endTagOther(token); } @@ -3566,9 +3669,11 @@ case "html": return startTagHtml(token); case "frameset": - return startTagFrameset(token); + startTagFrameset(token); + return null; case "frame": - return startTagFrame(token); + startTagFrame(token); + return null; case "noframes": return startTagNoframes(token); default: @@ -3579,9 +3684,11 @@ processEndTag(EndTagToken token) { switch (token.name) { case "frameset": - return endTagFrameset(token); + endTagFrameset(token); + return null; default: - return endTagOther(token); + endTagOther(token); + return null; } } @@ -3653,16 +3760,19 @@ case "noframes": return startTagNoframes(token); default: - return startTagOther(token); + startTagOther(token); + return null; } } processEndTag(EndTagToken token) { switch (token.name) { case "html": - return endTagHtml(token); + endTagHtml(token); + return null; default: - return endTagOther(token); + endTagOther(token); + return null; } } @@ -3748,7 +3858,8 @@ case "noframes": return startTagNoFrames(token); default: - return startTagOther(token); + startTagOther(token); + return null; } }
diff --git a/lib/src/css_class_set.dart b/lib/src/css_class_set.dart index 2e131a5..c7927b8 100644 --- a/lib/src/css_class_set.dart +++ b/lib/src/css_class_set.dart
@@ -55,7 +55,7 @@ * This is the Dart equivalent of jQuery's * [hasClass](http://api.jquery.com/hasClass/). */ - bool contains(String value); + bool contains(Object value); /** * Add the class [value] to element. @@ -93,7 +93,7 @@ * This is the Dart equivalent of jQuery's * [removeClass](http://api.jquery.com/removeClass/). */ - void removeAll(Iterable<String> iterable); + void removeAll(Iterable<Object> iterable); /** * Toggles all classes specified in [iterable] on element. @@ -151,11 +151,11 @@ String join([String separator = ""]) => readClasses().join(separator); - Iterable map(f(String element)) => readClasses().map(f); + Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(String e)) => readClasses().map(f); Iterable<String> where(bool f(String element)) => readClasses().where(f); - Iterable expand(Iterable f(String element)) => readClasses().expand(f); + Iterable/*<T>*/ expand/*<T>*/(Iterable/*<T>*/ f(String element)) => readClasses().expand(f); bool every(bool f(String element)) => readClasses().every(f); @@ -171,8 +171,8 @@ return readClasses().reduce(combine); } - dynamic fold(dynamic initialValue, - dynamic combine(dynamic previousValue, String element)) { + dynamic/*=T*/ fold/*<T>*/(var/*=T*/ initialValue, + dynamic/*=T*/ combine(var/*=T*/ previousValue, String element)) { return readClasses().fold(initialValue, combine); } // interface Collection - END @@ -184,10 +184,10 @@ * This is the Dart equivalent of jQuery's * [hasClass](http://api.jquery.com/hasClass/). */ - bool contains(String value) => readClasses().contains(value); + bool contains(Object value) => readClasses().contains(value); /** Lookup from the Set interface. Not interesting for a String set. */ - String lookup(String value) => contains(value) ? value : null; + String lookup(Object value) => contains(value) ? value as String : null; /** * Add the class [value] to element. @@ -233,7 +233,7 @@ * This is the Dart equivalent of jQuery's * [removeClass](http://api.jquery.com/removeClass/). */ - void removeAll(Iterable<String> iterable) { + void removeAll(Iterable<Object> iterable) { modify((s) => s.removeAll(iterable)); } @@ -251,7 +251,7 @@ iterable.forEach((e) => toggle(e, shouldAdd)); } - void retainAll(Iterable<String> iterable) { + void retainAll(Iterable<Object> iterable) { modify((s) => s.retainAll(iterable)); } @@ -263,10 +263,10 @@ modify((s) => s.retainWhere(test)); } - bool containsAll(Iterable<String> collection) => + bool containsAll(Iterable<Object> collection) => readClasses().containsAll(collection); - Set<String> intersection(Set<String> other) => + Set<String> intersection(Set<Object> other) => readClasses().intersection(other); Set<String> union(Set<String> other) => readClasses().union(other); @@ -285,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()}) => + String firstWhere(bool test(String value), {String orElse()}) => readClasses().firstWhere(test, orElse: orElse); - dynamic lastWhere(bool test(String value), {Object orElse()}) => + String lastWhere(bool test(String value), {String orElse()}) => readClasses().lastWhere(test, orElse: orElse); String singleWhere(bool test(String value)) => readClasses().singleWhere(test);
diff --git a/lib/src/encoding_parser.dart b/lib/src/encoding_parser.dart index fd64ff9..0b84989 100644 --- a/lib/src/encoding_parser.dart +++ b/lib/src/encoding_parser.dart
@@ -121,6 +121,14 @@ } } +typedef bool _MethodHandler(); + +class _DispatchEntry { + final String pattern; + final _MethodHandler handler; + _DispatchEntry(this.pattern, this.handler); +} + /// Mini parser for detecting character encoding from meta elements. class EncodingParser { final EncodingBytes data; @@ -133,19 +141,19 @@ String getEncoding() { final methodDispatch = [ - ["<!--", handleComment], - ["<meta", handleMeta], - ["</", handlePossibleEndTag], - ["<!", handleOther], - ["<?", handleOther], - ["<", handlePossibleStartTag] + new _DispatchEntry("<!--", handleComment), + new _DispatchEntry("<meta", handleMeta), + new _DispatchEntry("</", handlePossibleEndTag), + new _DispatchEntry("<!", handleOther), + new _DispatchEntry("<?", handleOther), + new _DispatchEntry("<", handlePossibleStartTag), ]; try { for (;;) { for (var dispatch in methodDispatch) { - if (data.matchBytes(dispatch[0])) { - var keepParsing = dispatch[1](); + if (data.matchBytes(dispatch.pattern)) { + var keepParsing = dispatch.handler(); if (keepParsing) break; // We found an encoding. Stop. @@ -154,7 +162,7 @@ } data.position += 1; } - } on StateError catch (e) { + } on StateError catch (_) { // Catch this here to match behavior of Python's StopIteration // TODO(jmesserly): refactor to not use exceptions } @@ -352,12 +360,12 @@ try { data.skipUntil(isWhitespace); return data.slice(oldPosition, data.position); - } on StateError catch (e) { + } on StateError catch (_) { //Return the whole remaining value return data.slice(oldPosition); } } - } on StateError catch (e) { + } on StateError catch (_) { return null; } }
diff --git a/lib/src/list_proxy.dart b/lib/src/list_proxy.dart index 99acdb6..5df1ed4 100644 --- a/lib/src/list_proxy.dart +++ b/lib/src/list_proxy.dart
@@ -20,11 +20,14 @@ // TODO(jmesserly): This should be on List. // See http://code.google.com/p/dart/issues/detail?id=947 - bool remove(E item) { - int i = indexOf(item); - if (i == -1) return false; - removeAt(i); - return true; + bool remove(Object item) { + if (item is E) { + int i = indexOf(item); + if (i == -1) return false; + removeAt(i); + return true; + } + return false; } void insert(int index, E item) => _list.insert(index, item); @@ -81,7 +84,7 @@ List<E> getRange(int start, int end) => _list.getRange(start, end); - void setRange(int start, int length, List<E> from, [int startFrom = 0]) { + void setRange(int start, int length, Iterable<E> from, [int startFrom = 0]) { _list.setRange(start, length, from, startFrom); } void removeRange(int start, int length) {
diff --git a/lib/src/query_selector.dart b/lib/src/query_selector.dart index e586d1a..3aa45f2 100644 --- a/lib/src/query_selector.dart +++ b/lib/src/query_selector.dart
@@ -3,6 +3,7 @@ import 'package:csslib/parser.dart' as css; import 'package:csslib/parser.dart' show TokenKind; +import 'package:csslib/src/messages.dart' show Message; import 'package:csslib/visitor.dart'; // the CSSOM import 'package:html/dom.dart'; import 'package:html/src/constants.dart' show isWhitespaceCC; @@ -14,7 +15,7 @@ new SelectorEvaluator().querySelector(node, _parseSelectorList(selector)); List<Element> querySelectorAll(Node node, String selector) { - var results = []; + var results = <Element>[]; new SelectorEvaluator().querySelectorAll( node, _parseSelectorList(selector), results); return results; @@ -22,7 +23,7 @@ // http://dev.w3.org/csswg/selectors-4/#grouping SelectorGroup _parseSelectorList(String selector) { - var errors = []; + var errors = <Message>[]; var group = css.parseSelectorGroup(selector, errors: errors); if (group == null || errors.isNotEmpty) { throw new FormatException("'$selector' is not a valid selector: $errors");
diff --git a/lib/src/tokenizer.dart b/lib/src/tokenizer.dart index 3273858..68cb6dc 100644 --- a/lib/src/tokenizer.dart +++ b/lib/src/tokenizer.dart
@@ -12,7 +12,7 @@ // TODO(jmesserly): we could use a better data structure here like a trie, if // we had it implemented in Dart. Map<String, List<String>> entitiesByFirstChar = (() { - var result = {}; + var result = <String, List<String>>{}; for (var k in entities.keys) { result.putIfAbsent(k[0], () => []).add(k); }
diff --git a/lib/src/utils.dart b/lib/src/utils.dart index fb58cf1..16837b0 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart
@@ -43,7 +43,7 @@ } // Like the python [:] operator. -List slice(List list, int start, [int end]) { +List/*<T>*/ slice/*<T>*/(List/*<T>*/ list, int start, [int end]) { if (end == null) end = list.length; if (end < 0) end += list.length;
diff --git a/pubspec.yaml b/pubspec.yaml index 697d1c8..4a595c1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml
@@ -1,12 +1,12 @@ name: html -version: 0.12.2+2 +version: 0.13.0 author: Dart Team <misc@dartlang.org> description: A library for working with HTML documents. Previously known as html5lib. homepage: https://github.com/dart-lang/html environment: sdk: '>=1.2.0 <2.0.0' dependencies: - csslib: '>=0.10.0 <0.14.0' + csslib: '>=0.13.2 <0.14.0' source_span: '>=1.0.0 <2.0.0' utf: '>=0.9.0 <0.10.0' dev_dependencies:
diff --git a/test/dom_test.dart b/test/dom_test.dart index d4e0809..404a488 100644 --- a/test/dom_test.dart +++ b/test/dom_test.dart
@@ -26,8 +26,8 @@ test('getElementById', () { var foo = doc.body.nodes[0]; var Foo = foo.nodes[2]; - expect(foo.id, 'foo'); - expect(Foo.id, 'Foo'); + expect((foo as Element).id, 'foo'); + expect((Foo as Element).id, 'Foo'); expect(doc.getElementById('foo'), foo); expect(doc.getElementById('Foo'), Foo); }); @@ -36,8 +36,8 @@ var foo = doc.body.nodes[0]; var barBaz = foo.nodes[0]; var quxBaz = foo.nodes[1]; - expect(barBaz.className, ' bar baz'); - expect(quxBaz.className, 'qux baz '); + expect((barBaz as Element).className, ' bar baz'); + expect((quxBaz as Element).className, 'qux baz '); expect(doc.getElementsByClassName('baz'), [barBaz, quxBaz]); expect(doc.getElementsByClassName('bar '), [barBaz]); expect(doc.getElementsByClassName(' qux'), [quxBaz]); @@ -57,83 +57,83 @@ test('add', () { var doc = parse('<body>'); doc.body.nodes.add(parseFragment('<x-foo>')); - expect(doc.body.nodes[0].localName, 'x-foo'); + expect((doc.body.nodes[0] as Element).localName, 'x-foo'); doc.body.nodes.add(parseFragment('<x-bar>')); - expect(doc.body.nodes[1].localName, 'x-bar'); + expect((doc.body.nodes[1] as Element).localName, 'x-bar'); }); test('addLast', () { var doc = parse('<body>'); doc.body.nodes.addLast(parseFragment('<x-foo>')); - expect(doc.body.nodes[0].localName, 'x-foo'); + expect((doc.body.nodes[0] as Element).localName, 'x-foo'); doc.body.nodes.addLast(parseFragment('<x-bar>')); - expect(doc.body.nodes[1].localName, 'x-bar'); + expect((doc.body.nodes[1] as Element).localName, 'x-bar'); }); test('addAll', () { var doc = parse('<body><x-a></x-a>'); doc.body.nodes.addAll([parseFragment('<x-b></x-b><x-c></x-c>')]); - expect(doc.body.nodes[0].localName, 'x-a'); - expect(doc.body.nodes[1].localName, 'x-b'); - expect(doc.body.nodes[2].localName, 'x-c'); + expect((doc.body.nodes[0] as Element).localName, 'x-a'); + expect((doc.body.nodes[1] as Element).localName, 'x-b'); + expect((doc.body.nodes[2] as Element).localName, 'x-c'); }); test('insert', () { var doc = parse('<body><x-a></x-a>'); doc.body.nodes.insert(0, parseFragment('<x-b></x-b><x-c></x-c>')); - expect(doc.body.nodes[0].localName, 'x-b'); - expect(doc.body.nodes[1].localName, 'x-c'); - expect(doc.body.nodes[2].localName, 'x-a'); + expect((doc.body.nodes[0] as Element).localName, 'x-b'); + expect((doc.body.nodes[1] as Element).localName, 'x-c'); + expect((doc.body.nodes[2] as Element).localName, 'x-a'); doc = parse('<body><x-a></x-a>'); doc.body.nodes.insert(1, parseFragment('<x-b></x-b><x-c></x-c>')); - expect(doc.body.nodes[0].localName, 'x-a'); - expect(doc.body.nodes[1].localName, 'x-b'); - expect(doc.body.nodes[2].localName, 'x-c'); + expect((doc.body.nodes[0] as Element).localName, 'x-a'); + expect((doc.body.nodes[1] as Element).localName, 'x-b'); + expect((doc.body.nodes[2] as Element).localName, 'x-c'); doc = parse('<body><x-a></x-a>'); doc.body.nodes.insert(0, parseFragment('<x-b></x-b>')); doc.body.nodes.insert(1, parseFragment('<x-c></x-c>')); - expect(doc.body.nodes[0].localName, 'x-b'); - expect(doc.body.nodes[1].localName, 'x-c'); - expect(doc.body.nodes[2].localName, 'x-a'); + expect((doc.body.nodes[0] as Element).localName, 'x-b'); + expect((doc.body.nodes[1] as Element).localName, 'x-c'); + expect((doc.body.nodes[2] as Element).localName, 'x-a'); }); test('insertAll', () { var doc = parse('<body><x-a></x-a>'); doc.body.nodes.insertAll(0, [parseFragment('<x-b></x-b><x-c></x-c>')]); - expect(doc.body.nodes[0].localName, 'x-b'); - expect(doc.body.nodes[1].localName, 'x-c'); - expect(doc.body.nodes[2].localName, 'x-a'); + expect((doc.body.nodes[0] as Element).localName, 'x-b'); + expect((doc.body.nodes[1] as Element).localName, 'x-c'); + expect((doc.body.nodes[2] as Element).localName, 'x-a'); expect(doc.body.nodes.length, 3); doc = parse('<body><x-a></x-a>'); doc.body.nodes.insertAll(1, [parseFragment('<x-b></x-b><x-c></x-c>')]); - expect(doc.body.nodes[0].localName, 'x-a'); - expect(doc.body.nodes[1].localName, 'x-b'); - expect(doc.body.nodes[2].localName, 'x-c'); + expect((doc.body.nodes[0] as Element).localName, 'x-a'); + expect((doc.body.nodes[1] as Element).localName, 'x-b'); + expect((doc.body.nodes[2] as Element).localName, 'x-c'); doc = parse('<body><x-a></x-a>'); doc.body.nodes.insertAll(0, [parseFragment('<x-b></x-b>')]); doc.body.nodes.insertAll(1, [parseFragment('<x-c></x-c>')]); - expect(doc.body.nodes[0].localName, 'x-b'); - expect(doc.body.nodes[1].localName, 'x-c'); - expect(doc.body.nodes[2].localName, 'x-a'); + expect((doc.body.nodes[0] as Element).localName, 'x-b'); + expect((doc.body.nodes[1] as Element).localName, 'x-c'); + expect((doc.body.nodes[2] as Element).localName, 'x-a'); }); test('operator []=', () { var doc = parse('<body><x-a></x-a>'); doc.body.nodes[0] = parseFragment('<x-b></x-b><x-c></x-c>'); - expect(doc.body.nodes[0].localName, 'x-b'); - expect(doc.body.nodes[1].localName, 'x-c'); + expect((doc.body.nodes[0] as Element).localName, 'x-b'); + expect((doc.body.nodes[1] as Element).localName, 'x-c'); expect(doc.body.nodes.length, 2); doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>'); doc.body.nodes[1] = parseFragment('<y-b></y-b><y-c></y-c>'); - expect(doc.body.nodes[0].localName, 'x-a'); - expect(doc.body.nodes[1].localName, 'y-b'); - expect(doc.body.nodes[2].localName, 'y-c'); - expect(doc.body.nodes[3].localName, 'x-c'); + expect((doc.body.nodes[0] as Element).localName, 'x-a'); + expect((doc.body.nodes[1] as Element).localName, 'y-b'); + expect((doc.body.nodes[2] as Element).localName, 'y-c'); + expect((doc.body.nodes[3] as Element).localName, 'x-c'); expect(doc.body.nodes.length, 4); }); @@ -141,18 +141,18 @@ var fragment = parseFragment('<y-b></y-b><y-c></y-c>'); var doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>'); doc.body.nodes.setRange(1, 2, fragment.nodes, 0); - expect(doc.body.nodes[0].localName, 'x-a'); - expect(doc.body.nodes[1].localName, 'y-b'); - expect(doc.body.nodes[2].localName, 'y-c'); + expect((doc.body.nodes[0] as Element).localName, 'x-a'); + expect((doc.body.nodes[1] as Element).localName, 'y-b'); + expect((doc.body.nodes[2] as Element).localName, 'y-c'); expect(doc.body.nodes.length, 3); fragment = parseFragment('<y-b></y-b><y-c></y-c>'); doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>'); doc.body.nodes.setRange(1, 1, [fragment], 0); - expect(doc.body.nodes[0].localName, 'x-a'); - expect(doc.body.nodes[1].localName, 'y-b'); - expect(doc.body.nodes[2].localName, 'y-c'); - expect(doc.body.nodes[3].localName, 'x-c'); + expect((doc.body.nodes[0] as Element).localName, 'x-a'); + expect((doc.body.nodes[1] as Element).localName, 'y-b'); + expect((doc.body.nodes[2] as Element).localName, 'y-c'); + expect((doc.body.nodes[3] as Element).localName, 'x-c'); expect(doc.body.nodes.length, 4); }); @@ -160,19 +160,19 @@ var fragment = parseFragment('<y-b></y-b><y-c></y-c>'); var doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>'); doc.body.nodes.replaceRange(1, 2, fragment.nodes); - expect(doc.body.nodes[0].localName, 'x-a'); - expect(doc.body.nodes[1].localName, 'y-b'); - expect(doc.body.nodes[2].localName, 'y-c'); - expect(doc.body.nodes[3].localName, 'x-c'); + expect((doc.body.nodes[0] as Element).localName, 'x-a'); + expect((doc.body.nodes[1] as Element).localName, 'y-b'); + expect((doc.body.nodes[2] as Element).localName, 'y-c'); + expect((doc.body.nodes[3] as Element).localName, 'x-c'); expect(doc.body.nodes.length, 4); fragment = parseFragment('<y-b></y-b><y-c></y-c>'); doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>'); doc.body.nodes.replaceRange(1, 2, [fragment]); - expect(doc.body.nodes[0].localName, 'x-a'); - expect(doc.body.nodes[1].localName, 'y-b'); - expect(doc.body.nodes[2].localName, 'y-c'); - expect(doc.body.nodes[3].localName, 'x-c'); + expect((doc.body.nodes[0] as Element).localName, 'x-a'); + expect((doc.body.nodes[1] as Element).localName, 'y-b'); + expect((doc.body.nodes[2] as Element).localName, 'y-c'); + expect((doc.body.nodes[3] as Element).localName, 'x-c'); expect(doc.body.nodes.length, 4); }); @@ -180,10 +180,10 @@ var fragment = parseFragment('<y-b></y-b><y-c></y-c>'); var doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>'); doc.body.nodes[1].replaceWith(fragment); - expect(doc.body.nodes[0].localName, 'x-a'); - expect(doc.body.nodes[1].localName, 'y-b'); - expect(doc.body.nodes[2].localName, 'y-c'); - expect(doc.body.nodes[3].localName, 'x-c'); + expect((doc.body.nodes[0] as Element).localName, 'x-a'); + expect((doc.body.nodes[1] as Element).localName, 'y-b'); + expect((doc.body.nodes[2] as Element).localName, 'y-c'); + expect((doc.body.nodes[3] as Element).localName, 'x-c'); expect(doc.body.nodes.length, 4); }); });
diff --git a/test/parser_feature_test.dart b/test/parser_feature_test.dart index 54d68a9..6d3af0c 100644 --- a/test/parser_feature_test.dart +++ b/test/parser_feature_test.dart
@@ -25,12 +25,12 @@ test('namespace html elements on', () { var doc = new HtmlParser('', tree: new TreeBuilder(true)).parse(); - expect(doc.nodes[0].namespaceUri, Namespaces.html); + expect((doc.nodes[0] as Element).namespaceUri, Namespaces.html); }); test('namespace html elements off', () { var doc = new HtmlParser('', tree: new TreeBuilder(false)).parse(); - expect(doc.nodes[0].namespaceUri, null); + expect((doc.nodes[0] as Element).namespaceUri, null); }); test('parse error spans - full', () { @@ -290,7 +290,7 @@ expect(e.text, 'bar'); c.text = 'qux'; - expect(c.data, 'qux'); + expect((c as Comment).data, 'qux'); expect(c.text, 'qux'); expect(e.text, 'bar'); }); @@ -310,7 +310,7 @@ }); group('Encoding pre-parser', () { - getEncoding(s) => new EncodingParser(s.codeUnits).getEncoding(); + getEncoding(String s) => new EncodingParser(s.codeUnits).getEncoding(); test('gets encoding from meta charset', () { expect(getEncoding('<meta charset="utf-16">'), 'utf-16'); @@ -473,4 +473,4 @@ } }); }); -} \ No newline at end of file +}
diff --git a/test/run_all.dart b/test/run_all.dart index 14e6b34..d2bf9ce 100644 --- a/test/run_all.dart +++ b/test/run_all.dart
@@ -17,7 +17,7 @@ var pattern = new RegExp(args.length > 0 ? args[0] : '.'); useCompactVMConfiguration(); - void addGroup(testFile, testMain) { + void addGroup(testFile, void testMain()) { if (pattern.hasMatch(testFile)) { group(testFile.replaceAll('_test.dart', ':'), testMain); }
diff --git a/test/support.dart b/test/support.dart index 1b4c0b4..1bb2550 100644 --- a/test/support.dart +++ b/test/support.dart
@@ -10,7 +10,7 @@ typedef TreeBuilder TreeBuilderFactory(bool namespaceHTMLElements); -Map _treeTypes; +Map<String, TreeBuilderFactory> _treeTypes; Map<String, TreeBuilderFactory> get treeTypes { if (_treeTypes == null) { // TODO(jmesserly): add DOM here once it's implemented @@ -133,13 +133,16 @@ indent -= 2; } - visitDocument(node) { + visitDocument(node) => _visitDocumentOrFragment(node); + + _visitDocumentOrFragment(node) { indent += 1; for (var child in node.nodes) visit(child); indent -= 1; } - visitDocumentFragment(DocumentFragment node) => visitDocument(node); + visitDocumentFragment(DocumentFragment node) => + _visitDocumentOrFragment(node); visitElement(Element node) { _newline();