mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:39:48 +00:00
[html5lib] triple slash comment style
Also improves ./tools/line_doc_comments.dart to warn about lines >= 80 chars, to make it easier to catch these. R=sigmund@google.com Review URL: https://codereview.chromium.org//178843003 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@32997 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
6e2de7cdf1
commit
d48a43957f
144
pkg/third_party/html5lib/lib/dom.dart
vendored
144
pkg/third_party/html5lib/lib/dom.dart
vendored
|
@ -1,7 +1,5 @@
|
|||
/**
|
||||
* A simple tree API that results from parsing html. Intended to be compatible
|
||||
* with dart:html, but right now it resembles the classic JS DOM.
|
||||
*/
|
||||
/// A simple tree API that results from parsing html. Intended to be compatible
|
||||
/// with dart:html, but right now it resembles the classic JS DOM.
|
||||
library dom;
|
||||
|
||||
import 'dart:collection';
|
||||
|
@ -18,13 +16,13 @@ import 'parser.dart';
|
|||
// TODO(jmesserly): this needs to be replaced by an AttributeMap for attributes
|
||||
// that exposes namespace info.
|
||||
class AttributeName implements Comparable {
|
||||
/** The namespace prefix, e.g. `xlink`. */
|
||||
/// The namespace prefix, e.g. `xlink`.
|
||||
final String prefix;
|
||||
|
||||
/** The attribute name, e.g. `title`. */
|
||||
/// The attribute name, e.g. `title`.
|
||||
final String name;
|
||||
|
||||
/** The namespace url, e.g. `http://www.w3.org/1999/xlink` */
|
||||
/// The namespace url, e.g. `http://www.w3.org/1999/xlink`
|
||||
final String namespace;
|
||||
|
||||
const AttributeName(this.prefix, this.name, this.namespace);
|
||||
|
@ -62,7 +60,7 @@ class AttributeName implements Comparable {
|
|||
}
|
||||
}
|
||||
|
||||
/** Really basic implementation of a DOM-core like Node. */
|
||||
/// Really basic implementation of a DOM-core like Node.
|
||||
abstract class Node {
|
||||
static const int ATTRIBUTE_NODE = 2;
|
||||
static const int CDATA_SECTION_NODE = 4;
|
||||
|
@ -78,35 +76,31 @@ abstract class Node {
|
|||
static const int TEXT_NODE = 3;
|
||||
|
||||
// TODO(jmesserly): this should be on Element
|
||||
/** The tag name associated with the node. */
|
||||
/// The tag name associated with the node.
|
||||
final String tagName;
|
||||
|
||||
/** The parent of the current node (or null for the document node). */
|
||||
/// The parent of the current node (or null for the document node).
|
||||
Node parent;
|
||||
|
||||
// TODO(jmesserly): should move to Element.
|
||||
/**
|
||||
* A map holding name, value pairs for attributes of the node.
|
||||
*
|
||||
* Note that attribute order needs to be stable for serialization, so we use a
|
||||
* LinkedHashMap. Each key is a [String] or [AttributeName].
|
||||
*/
|
||||
/// A map holding name, value pairs for attributes of the node.
|
||||
///
|
||||
/// Note that attribute order needs to be stable for serialization, so we use
|
||||
/// a LinkedHashMap. Each key is a [String] or [AttributeName].
|
||||
LinkedHashMap<dynamic, String> attributes = new LinkedHashMap();
|
||||
|
||||
/**
|
||||
* A list of child nodes of the current node. This must
|
||||
* include all elements but not necessarily other node types.
|
||||
*/
|
||||
/// A list of child nodes of the current node. This must
|
||||
/// include all elements but not necessarily other node types.
|
||||
final NodeList nodes = new NodeList._();
|
||||
|
||||
List<Element> _elements;
|
||||
|
||||
// TODO(jmesserly): consider using an Expando for this, and put it in
|
||||
// dom_parsing. Need to check the performance affect.
|
||||
/** The source span of this node, if it was created by the [HtmlParser]. */
|
||||
/// The source span of this node, if it was created by the [HtmlParser].
|
||||
FileSpan sourceSpan;
|
||||
|
||||
/** The attribute spans if requested. Otherwise null. */
|
||||
/// The attribute spans if requested. Otherwise null.
|
||||
LinkedHashMap<dynamic, FileSpan> _attributeSpans;
|
||||
LinkedHashMap<dynamic, FileSpan> _attributeValueSpans;
|
||||
|
||||
|
@ -114,23 +108,19 @@ abstract class Node {
|
|||
nodes._parent = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If [sourceSpan] is available, this contains the spans of each attribute.
|
||||
* The span of an attribute is the entire attribute, including the name and
|
||||
* quotes (if any). For example, the span of "attr" in `<a attr="value">`
|
||||
* would be the text `attr="value"`.
|
||||
*/
|
||||
/// If [sourceSpan] is available, this contains the spans of each attribute.
|
||||
/// The span of an attribute is the entire attribute, including the name and
|
||||
/// quotes (if any). For example, the span of "attr" in `<a attr="value">`
|
||||
/// would be the text `attr="value"`.
|
||||
LinkedHashMap<dynamic, FileSpan> get attributeSpans {
|
||||
_ensureAttributeSpans();
|
||||
return _attributeSpans;
|
||||
}
|
||||
|
||||
/**
|
||||
* If [sourceSpan] is available, this contains the spans of each attribute's
|
||||
* value. Unlike [attributeSpans], this span will inlcude only the value.
|
||||
* For example, the value span of "attr" in `<a attr="value">` would be the
|
||||
* text `value`.
|
||||
*/
|
||||
/// If [sourceSpan] is available, this contains the spans of each attribute's
|
||||
/// value. Unlike [attributeSpans], this span will inlcude only the value.
|
||||
/// For example, the value span of "attr" in `<a attr="value">` would be the
|
||||
/// text `value`.
|
||||
LinkedHashMap<dynamic, FileSpan> get attributeValueSpans {
|
||||
_ensureAttributeSpans();
|
||||
return _attributeValueSpans;
|
||||
|
@ -144,20 +134,18 @@ abstract class Node {
|
|||
}
|
||||
|
||||
// TODO(jmesserly): needs to support deep clone.
|
||||
/**
|
||||
* Return a shallow copy of the current node i.e. a node with the same
|
||||
* name and attributes but with no parent or child nodes.
|
||||
*/
|
||||
/// Return a shallow copy of the current node i.e. a node with the same
|
||||
/// name and attributes but with no parent or child nodes.
|
||||
Node clone();
|
||||
|
||||
String get namespace => null;
|
||||
|
||||
int get nodeType;
|
||||
|
||||
/** *Deprecated* use [text], [Text.data] or [Comment.data]. */
|
||||
/// *Deprecated* use [text], [Text.data] or [Comment.data].
|
||||
@deprecated String get value => null;
|
||||
|
||||
/** *Deprecated* use [nodeType]. */
|
||||
/// *Deprecated* use [nodeType].
|
||||
@deprecated int get $dom_nodeType => nodeType;
|
||||
|
||||
String get outerHtml {
|
||||
|
@ -203,12 +191,10 @@ abstract class Node {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert [node] as a child of the current node, before [refNode] in the
|
||||
* list of child nodes. Raises [UnsupportedOperationException] if [refNode]
|
||||
* is not a child of the current node. If refNode is null, this adds to the
|
||||
* end of the list.
|
||||
*/
|
||||
/// Insert [node] as a child of the current node, before [refNode] in the
|
||||
/// list of child nodes. Raises [UnsupportedOperationException] if [refNode]
|
||||
/// is not a child of the current node. If refNode is null, this adds to the
|
||||
/// end of the list.
|
||||
void insertBefore(Node node, Node refNode) {
|
||||
if (refNode == null) {
|
||||
nodes.add(node);
|
||||
|
@ -217,7 +203,7 @@ abstract class Node {
|
|||
}
|
||||
}
|
||||
|
||||
/** Replaces this node with another node. */
|
||||
/// Replaces this node with another node.
|
||||
Node replaceWith(Node otherNode) {
|
||||
if (parent == null) {
|
||||
throw new UnsupportedError('Node must have a parent to replace it.');
|
||||
|
@ -227,7 +213,7 @@ abstract class Node {
|
|||
}
|
||||
|
||||
// TODO(jmesserly): should this be a property or remove?
|
||||
/** Return true if the node has children or text. */
|
||||
/// Return true if the node has children or text.
|
||||
bool hasContent() => nodes.length > 0;
|
||||
|
||||
Pair<String, String> get nameTuple {
|
||||
|
@ -235,38 +221,32 @@ abstract class Node {
|
|||
return new Pair(ns, tagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move all the children of the current node to [newParent].
|
||||
* This is needed so that trees that don't store text as nodes move the
|
||||
* text in the correct way.
|
||||
*/
|
||||
/// Move all the children of the current node to [newParent].
|
||||
/// This is needed so that trees that don't store text as nodes move the
|
||||
/// text in the correct way.
|
||||
void reparentChildren(Node newParent) {
|
||||
newParent.nodes.addAll(nodes);
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
/** *Deprecated* use [querySelector] instead. */
|
||||
/// *Deprecated* use [querySelector] instead.
|
||||
@deprecated
|
||||
Element query(String selectors) => querySelector(selectors);
|
||||
|
||||
/** *Deprecated* use [querySelectorAll] instead. */
|
||||
/// *Deprecated* use [querySelectorAll] instead.
|
||||
@deprecated
|
||||
List<Element> queryAll(String selectors) => querySelectorAll(selectors);
|
||||
|
||||
/**
|
||||
* Seaches for the first descendant node matching the given selectors, using a
|
||||
* preorder traversal. NOTE: right now, this supports only a single type
|
||||
* selectors, e.g. `node.query('div')`.
|
||||
*/
|
||||
/// Seaches for the first descendant node matching the given selectors, using a
|
||||
/// preorder traversal. NOTE: right now, this supports only a single type
|
||||
/// selectors, e.g. `node.query('div')`.
|
||||
|
||||
Element querySelector(String selectors) =>
|
||||
_queryType(_typeSelector(selectors));
|
||||
|
||||
/**
|
||||
* Returns all descendant nodes matching the given selectors, using a
|
||||
* preorder traversal. NOTE: right now, this supports only a single type
|
||||
* selectors, e.g. `node.queryAll('div')`.
|
||||
*/
|
||||
/// Returns all descendant nodes matching the given selectors, using a
|
||||
/// preorder traversal. NOTE: right now, this supports only a single type
|
||||
/// selectors, e.g. `node.queryAll('div')`.
|
||||
List<Element> querySelectorAll(String selectors) {
|
||||
var results = new List<Element>();
|
||||
_queryAllType(_typeSelector(selectors), results);
|
||||
|
@ -285,12 +265,10 @@ abstract class Node {
|
|||
return selectors;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
/// 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:
|
||||
|
||||
|
@ -345,7 +323,7 @@ abstract class Node {
|
|||
}
|
||||
}
|
||||
|
||||
/** Initialize [attributeSpans] using [sourceSpan]. */
|
||||
/// Initialize [attributeSpans] using [sourceSpan].
|
||||
void _ensureAttributeSpans() {
|
||||
if (_attributeSpans != null) return;
|
||||
|
||||
|
@ -439,7 +417,7 @@ class Text extends Node {
|
|||
|
||||
Text(this.data) : super(null);
|
||||
|
||||
/** *Deprecated* use [data]. */
|
||||
/// *Deprecated* use [data].
|
||||
@deprecated String get value => data;
|
||||
@deprecated set value(String x) { data = x; }
|
||||
|
||||
|
@ -720,10 +698,8 @@ class NodeList extends ListProxy<Node> {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* An indexable collection of a node's descendants in the document tree,
|
||||
* filtered so that only elements are in the collection.
|
||||
*/
|
||||
/// 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>
|
||||
|
@ -732,14 +708,12 @@ class FilteredElementList extends IterableBase<Element> with ListMixin<Element>
|
|||
final Node _node;
|
||||
final List<Node> _childNodes;
|
||||
|
||||
/**
|
||||
* Creates a collection of the elements that descend from a node.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* var filteredElements = new FilteredElementList(query("#container"));
|
||||
* // filteredElements is [a, b, c].
|
||||
*/
|
||||
/// Creates a collection of the elements that descend from a node.
|
||||
///
|
||||
/// Example usage:
|
||||
///
|
||||
/// var filteredElements = new FilteredElementList(query("#container"));
|
||||
/// // filteredElements is [a, b, c].
|
||||
FilteredElementList(Node node): _childNodes = node.nodes, _node = node;
|
||||
|
||||
// We can't memoize this, since it's possible that children will be messed
|
||||
|
|
74
pkg/third_party/html5lib/lib/dom_parsing.dart
vendored
74
pkg/third_party/html5lib/lib/dom_parsing.dart
vendored
|
@ -1,12 +1,10 @@
|
|||
/**
|
||||
* This library contains extra APIs that aren't in the DOM, but are useful
|
||||
* when interacting with the parse tree.
|
||||
*/
|
||||
/// This library contains extra APIs that aren't in the DOM, but are useful
|
||||
/// when interacting with the parse tree.
|
||||
library dom_parsing;
|
||||
|
||||
import 'dom.dart';
|
||||
|
||||
/** A simple tree visitor for the DOM nodes. */
|
||||
/// A simple tree visitor for the DOM nodes.
|
||||
class TreeVisitor {
|
||||
visit(Node node) {
|
||||
switch (node.nodeType) {
|
||||
|
@ -25,11 +23,9 @@ class TreeVisitor {
|
|||
for (var child in node.nodes.toList()) visit(child);
|
||||
}
|
||||
|
||||
/**
|
||||
* The fallback handler if the more specific visit method hasn't been
|
||||
* overriden. Only use this from a subclass of [TreeVisitor], otherwise
|
||||
* call [visit] instead.
|
||||
*/
|
||||
/// The fallback handler if the more specific visit method hasn't been
|
||||
/// overriden. Only use this from a subclass of [TreeVisitor], otherwise
|
||||
/// call [visit] instead.
|
||||
visitNodeFallback(Node node) => visitChildren(node);
|
||||
|
||||
visitDocument(Document node) => visitNodeFallback(node);
|
||||
|
@ -47,20 +43,16 @@ class TreeVisitor {
|
|||
visitDocumentFragment(DocumentFragment node) => visitDocument(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the DOM tree into an HTML string with code markup suitable for
|
||||
* displaying the HTML's source code with CSS colors for different parts of the
|
||||
* markup. See also [CodeMarkupVisitor].
|
||||
*/
|
||||
/// Converts the DOM tree into an HTML string with code markup suitable for
|
||||
/// displaying the HTML's source code with CSS colors for different parts of the
|
||||
/// markup. See also [CodeMarkupVisitor].
|
||||
String htmlToCodeMarkup(Node node) {
|
||||
return (new CodeMarkupVisitor()..visit(node)).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the DOM tree into an HTML string with code markup suitable for
|
||||
* displaying the HTML's source code with CSS colors for different parts of the
|
||||
* markup. See also [htmlToCodeMarkup].
|
||||
*/
|
||||
/// Converts the DOM tree into an HTML string with code markup suitable for
|
||||
/// displaying the HTML's source code with CSS colors for different parts of the
|
||||
/// markup. See also [htmlToCodeMarkup].
|
||||
class CodeMarkupVisitor extends TreeVisitor {
|
||||
final StringBuffer _str;
|
||||
|
||||
|
@ -113,23 +105,21 @@ class CodeMarkupVisitor extends TreeVisitor {
|
|||
|
||||
// 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
|
||||
* [HTML fragment serialization algorithm][1]. In particular, as described
|
||||
* in the [specification][2]:
|
||||
*
|
||||
* - Replace any occurrence of the `&` character by the string `&`.
|
||||
* - Replace any occurrences of the U+00A0 NO-BREAK SPACE character by the
|
||||
* string ` `.
|
||||
* - If the algorithm was invoked in [attributeMode], replace any occurrences of
|
||||
* the `"` character by the string `"`.
|
||||
* - If the algorithm was not invoked in [attributeMode], replace any
|
||||
* occurrences of the `<` character by the string `<`, and any occurrences
|
||||
* of the `>` character by the string `>`.
|
||||
*
|
||||
* [1]: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#serializing-html-fragments
|
||||
* [2]: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#escapingString
|
||||
*/
|
||||
/// Escapes [text] for use in the
|
||||
/// [HTML fragment serialization algorithm][1]. In particular, as described
|
||||
/// in the [specification][2]:
|
||||
///
|
||||
/// - Replace any occurrence of the `&` character by the string `&`.
|
||||
/// - Replace any occurrences of the U+00A0 NO-BREAK SPACE character by the
|
||||
/// string ` `.
|
||||
/// - If the algorithm was invoked in [attributeMode], replace any occurrences
|
||||
/// of the `"` character by the string `"`.
|
||||
/// - If the algorithm was not invoked in [attributeMode], replace any
|
||||
/// occurrences of the `<` character by the string `<`, and any occurrences
|
||||
/// of the `>` character by the string `>`.
|
||||
///
|
||||
/// [1]: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#serializing-html-fragments
|
||||
/// [2]: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#escapingString
|
||||
String htmlSerializeEscape(String text, {bool attributeMode: false}) {
|
||||
// TODO(jmesserly): is it faster to build up a list of codepoints?
|
||||
// StringBuffer seems cleaner assuming Dart can unbox 1-char strings.
|
||||
|
@ -156,12 +146,10 @@ String htmlSerializeEscape(String text, {bool attributeMode: false}) {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 <http://dev.w3.org/html5/markup/syntax.html#void-elements> for more info.
|
||||
*/
|
||||
/// 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":
|
||||
|
|
186
pkg/third_party/html5lib/lib/parser.dart
vendored
186
pkg/third_party/html5lib/lib/parser.dart
vendored
|
@ -1,18 +1,16 @@
|
|||
/**
|
||||
* This library has a parser for HTML5 documents, that lets you parse HTML
|
||||
* easily from a script or server side application:
|
||||
*
|
||||
* import 'package:html5lib/parser.dart' show parse;
|
||||
* import 'package:html5lib/dom.dart';
|
||||
* main() {
|
||||
* var document = parse(
|
||||
* '<body>Hello world! <a href="www.html5rocks.com">HTML5 rocks!');
|
||||
* print(document.outerHtml);
|
||||
* }
|
||||
*
|
||||
* The resulting document you get back has a DOM-like API for easy tree
|
||||
* traversal and manipulation.
|
||||
*/
|
||||
/// This library has a parser for HTML5 documents, that lets you parse HTML
|
||||
/// easily from a script or server side application:
|
||||
///
|
||||
/// import 'package:html5lib/parser.dart' show parse;
|
||||
/// import 'package:html5lib/dom.dart';
|
||||
/// main() {
|
||||
/// var document = parse(
|
||||
/// '<body>Hello world! <a href="www.html5rocks.com">HTML5 rocks!');
|
||||
/// print(document.outerHtml);
|
||||
/// }
|
||||
///
|
||||
/// The resulting document you get back has a DOM-like API for easy tree
|
||||
/// traversal and manipulation.
|
||||
library parser;
|
||||
|
||||
import 'dart:collection';
|
||||
|
@ -27,19 +25,17 @@ import 'src/tokenizer.dart';
|
|||
import 'src/utils.dart';
|
||||
import 'dom.dart';
|
||||
|
||||
/**
|
||||
* Parse the [input] html5 document into a tree. The [input] can be
|
||||
* a [String], [List<int>] of bytes or an [HtmlTokenizer].
|
||||
*
|
||||
* If [input] is not a [HtmlTokenizer], you can optionally specify the file's
|
||||
* [encoding], which must be a string. If specified, that encoding will be used,
|
||||
* regardless of any BOM or later declaration (such as in a meta element).
|
||||
*
|
||||
* Set [generateSpans] if you want to generate [Span]s, otherwise the
|
||||
* [Node.sourceSpan] property will be `null`. When using [generateSpans] you can
|
||||
* additionally pass [sourceUrl] to indicate where the [input] was extracted
|
||||
* from.
|
||||
*/
|
||||
/// Parse the [input] html5 document into a tree. The [input] can be
|
||||
/// a [String], [List<int>] of bytes or an [HtmlTokenizer].
|
||||
///
|
||||
/// If [input] is not a [HtmlTokenizer], you can optionally specify the file's
|
||||
/// [encoding], which must be a string. If specified that encoding will be
|
||||
/// used regardless of any BOM or later declaration (such as in a meta element).
|
||||
///
|
||||
/// Set [generateSpans] if you want to generate [Span]s, otherwise the
|
||||
/// [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,
|
||||
|
@ -48,20 +44,18 @@ Document parse(input, {String encoding, bool generateSpans: false,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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".
|
||||
*
|
||||
* If [input] is not a [HtmlTokenizer], you can optionally specify the file's
|
||||
* [encoding], which must be a string. If specified, that encoding will be used,
|
||||
* regardless of any BOM or later declaration (such as in a meta element).
|
||||
*
|
||||
* Set [generateSpans] if you want to generate [Span]s, otherwise the
|
||||
* [Node.sourceSpan] property will be `null`. When using [generateSpans] you can
|
||||
* additionally pass [sourceUrl] to indicate where the [input] was extracted
|
||||
* from.
|
||||
*/
|
||||
/// 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".
|
||||
///
|
||||
/// If [input] is not a [HtmlTokenizer], you can optionally specify the file's
|
||||
/// [encoding], which must be a string. If specified, that encoding will be used,
|
||||
/// regardless of any BOM or later declaration (such as in a meta element).
|
||||
///
|
||||
/// Set [generateSpans] if you want to generate [Span]s, otherwise the
|
||||
/// [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,
|
||||
|
@ -70,15 +64,13 @@ DocumentFragment parseFragment(input, {String container: "div",
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parser for HTML, which generates a tree structure from a stream of
|
||||
* (possibly malformed) characters.
|
||||
*/
|
||||
/// Parser for HTML, which generates a tree structure from a stream of
|
||||
/// (possibly malformed) characters.
|
||||
class HtmlParser {
|
||||
/** Raise an exception on the first error encountered. */
|
||||
/// Raise an exception on the first error encountered.
|
||||
final bool strict;
|
||||
|
||||
/** True to generate [Span]s for the [Node.sourceSpan] property. */
|
||||
/// True to generate [Span]s for the [Node.sourceSpan] property.
|
||||
final bool generateSpans;
|
||||
|
||||
final HtmlTokenizer tokenizer;
|
||||
|
@ -92,10 +84,10 @@ class HtmlParser {
|
|||
bool firstStartTag = false;
|
||||
|
||||
// TODO(jmesserly): use enum?
|
||||
/** "quirks" / "limited quirks" / "no quirks" */
|
||||
/// "quirks" / "limited quirks" / "no quirks"
|
||||
String compatMode = "no quirks";
|
||||
|
||||
/** innerHTML container when parsing document fragment. */
|
||||
/// innerHTML container when parsing document fragment.
|
||||
String innerHTML;
|
||||
|
||||
Phase phase;
|
||||
|
@ -133,23 +125,21 @@ class HtmlParser {
|
|||
AfterAfterBodyPhase _afterAfterBodyPhase;
|
||||
AfterAfterFramesetPhase _afterAfterFramesetPhase;
|
||||
|
||||
/**
|
||||
* Create a new HtmlParser and configure the [tree] builder and [strict] mode.
|
||||
* The [input] can be a [String], [List<int>] of bytes or an [HtmlTokenizer].
|
||||
*
|
||||
* If [input] is not a [HtmlTokenizer], you can specify a few more arguments.
|
||||
*
|
||||
* The [encoding] must be a string that indicates the encoding. If specified,
|
||||
* that encoding will be used, regardless of any BOM or later declaration
|
||||
* (such as in a meta element).
|
||||
*
|
||||
* Set [parseMeta] to false if you want to disable parsing the meta element.
|
||||
*
|
||||
* Set [lowercaseElementName] or [lowercaseAttrName] to false to disable the
|
||||
* automatic conversion of element and attribute names to lower case. Note
|
||||
* that standard way to parse HTML is to lowercase, which is what the browser
|
||||
* DOM will do if you request [Node.outerHTML], for example.
|
||||
*/
|
||||
/// Create an HtmlParser and configure the [tree] builder and [strict] mode.
|
||||
/// The [input] can be a [String], [List<int>] of bytes or an [HtmlTokenizer].
|
||||
///
|
||||
/// If [input] is not a [HtmlTokenizer], you can specify a few more arguments.
|
||||
///
|
||||
/// The [encoding] must be a string that indicates the encoding. If specified,
|
||||
/// that encoding will be used, regardless of any BOM or later declaration
|
||||
/// (such as in a meta element).
|
||||
///
|
||||
/// Set [parseMeta] to false if you want to disable parsing the meta element.
|
||||
///
|
||||
/// Set [lowercaseElementName] or [lowercaseAttrName] to false to disable the
|
||||
/// automatic conversion of element and attribute names to lower case. Note
|
||||
/// that standard way to parse HTML is to lowercase, which is what the browser
|
||||
/// DOM will do if you request [Node.outerHTML], for example.
|
||||
HtmlParser(input, {String encoding, bool parseMeta: true,
|
||||
bool lowercaseElementName: true, bool lowercaseAttrName: true,
|
||||
this.strict: false, bool generateSpans: false, String sourceUrl,
|
||||
|
@ -194,21 +184,17 @@ class HtmlParser {
|
|||
|
||||
bool get innerHTMLMode => innerHTML != null;
|
||||
|
||||
/**
|
||||
* Parse an html5 document into a tree.
|
||||
* After parsing, [errors] will be populated with parse errors, if any.
|
||||
*/
|
||||
/// Parse an html5 document into a tree.
|
||||
/// After parsing, [errors] will be populated with parse errors, if any.
|
||||
Document parse() {
|
||||
innerHTML = null;
|
||||
_parse();
|
||||
return tree.getDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an html5 document fragment into a tree.
|
||||
* Pass a [container] to change the type of the containing element.
|
||||
* After parsing, [errors] will be populated with parse errors, if any.
|
||||
*/
|
||||
/// Parse an html5 document fragment into a tree.
|
||||
/// Pass a [container] to change the type of the containing element.
|
||||
/// After parsing, [errors] will be populated with parse errors, if any.
|
||||
DocumentFragment parseFragment([String container = "div"]) {
|
||||
if (container == null) throw new ArgumentError('container');
|
||||
innerHTML = container.toLowerCase();
|
||||
|
@ -375,10 +361,8 @@ class HtmlParser {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The last span available. Used for EOF errors if we don't have something
|
||||
* better.
|
||||
*/
|
||||
/// The last span available. Used for EOF errors if we don't have something
|
||||
/// better.
|
||||
Span get _lastSpan {
|
||||
var pos = tokenizer.stream.position;
|
||||
return new FileSpan(tokenizer.stream.fileInfo, pos, pos);
|
||||
|
@ -544,10 +528,8 @@ class HtmlParser {
|
|||
phase = _inBodyPhase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic RCDATA/RAWTEXT Parsing algorithm
|
||||
* [contentType] - RCDATA or RAWTEXT
|
||||
*/
|
||||
/// Generic RCDATA/RAWTEXT Parsing algorithm
|
||||
/// [contentType] - RCDATA or RAWTEXT
|
||||
void parseRCDataRawtext(Token token, String contentType) {
|
||||
assert(contentType == "RAWTEXT" || contentType == "RCDATA");
|
||||
|
||||
|
@ -565,7 +547,7 @@ class HtmlParser {
|
|||
}
|
||||
|
||||
|
||||
/** Base class for helper object that implements each phase of processing. */
|
||||
/// Base class for helper object that implements each phase of processing.
|
||||
class Phase {
|
||||
// Order should be (they can be omitted):
|
||||
// * EOF
|
||||
|
@ -631,7 +613,7 @@ class Phase {
|
|||
throw new UnimplementedError();
|
||||
}
|
||||
|
||||
/** Helper method for popping openElements. */
|
||||
/// Helper method for popping openElements.
|
||||
void popOpenElementsUntil(String name) {
|
||||
var node = tree.openElements.removeLast();
|
||||
while (node.tagName != name) {
|
||||
|
@ -1568,7 +1550,7 @@ class InBodyPhase extends Phase {
|
|||
startTagRawtext(token);
|
||||
}
|
||||
|
||||
/** iframe, noembed noframes, noscript(if scripting enabled). */
|
||||
/// iframe, noembed noframes, noscript(if scripting enabled).
|
||||
void startTagRawtext(StartTagToken token) {
|
||||
parser.parseRCDataRawtext(token, "RAWTEXT");
|
||||
}
|
||||
|
@ -1637,13 +1619,11 @@ class InBodyPhase extends Phase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Elements that should be children of other elements that have a
|
||||
* different insertion mode; here they are ignored
|
||||
* "caption", "col", "colgroup", "frame", "frameset", "head",
|
||||
* "option", "optgroup", "tbody", "td", "tfoot", "th", "thead",
|
||||
* "tr", "noscript"
|
||||
*/
|
||||
/// Elements that should be children of other elements that have a
|
||||
/// different insertion mode; here they are ignored
|
||||
/// "caption", "col", "colgroup", "frame", "frameset", "head",
|
||||
/// "option", "optgroup", "tbody", "td", "tfoot", "th", "thead",
|
||||
/// "tr", "noscript"
|
||||
void startTagMisplaced(StartTagToken token) {
|
||||
parser.parseError(token.span, "unexpected-start-tag-ignored",
|
||||
{"name": token.name});
|
||||
|
@ -1770,7 +1750,7 @@ class InBodyPhase extends Phase {
|
|||
}
|
||||
}
|
||||
|
||||
/** The much-feared adoption agency algorithm. */
|
||||
/// The much-feared adoption agency algorithm.
|
||||
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
|
||||
|
@ -3350,7 +3330,7 @@ class AfterAfterFramesetPhase extends Phase {
|
|||
}
|
||||
|
||||
|
||||
/** Error in parsed document. */
|
||||
/// Error in parsed document.
|
||||
class ParseError implements Exception {
|
||||
final String errorCode;
|
||||
final Span span;
|
||||
|
@ -3362,14 +3342,12 @@ class ParseError implements Exception {
|
|||
|
||||
int get column => span.start.column;
|
||||
|
||||
/**
|
||||
* Gets the human readable error message for this error. Use
|
||||
* [span.getLocationMessage] or [toString] to get a message including span
|
||||
* information. If there is a file associated with the span, both
|
||||
* [span.getLocationMessage] and [toString] are equivalent. Otherwise,
|
||||
* [span.getLocationMessage] will not show any source url information, but
|
||||
* [toString] will include 'ParserError:' as a prefix.
|
||||
*/
|
||||
/// Gets the human readable error message for this error. Use
|
||||
/// [span.getLocationMessage] or [toString] to get a message including span
|
||||
/// information. If there is a file associated with the span, both
|
||||
/// [span.getLocationMessage] and [toString] are equivalent. Otherwise,
|
||||
/// [span.getLocationMessage] will not show any source url information, but
|
||||
/// [toString] will include 'ParserError:' as a prefix.
|
||||
String get message => formatStr(errorMessages[errorCode], data);
|
||||
|
||||
String toString() {
|
||||
|
|
18
pkg/third_party/html5lib/lib/parser_console.dart
vendored
18
pkg/third_party/html5lib/lib/parser_console.dart
vendored
|
@ -1,19 +1,15 @@
|
|||
/**
|
||||
* This library adds `dart:io` support to the HTML5 parser. Call
|
||||
* [initDartIOSupport] before calling the [parse] methods and they will accept
|
||||
* a [RandomAccessFile] as input, in addition to the other input types.
|
||||
*/
|
||||
/// This library adds `dart:io` support to the HTML5 parser. Call
|
||||
/// [initDartIOSupport] before calling the [parse] methods and they will accept
|
||||
/// a [RandomAccessFile] as input, in addition to the other input types.
|
||||
library parser_console;
|
||||
|
||||
import 'dart:io';
|
||||
import 'parser.dart';
|
||||
import 'src/inputstream.dart' as inputstream;
|
||||
|
||||
/**
|
||||
* Adds support to the [HtmlParser] for running on a console VM. In particular
|
||||
* this means it will be able to handle `dart:io` and [RandomAccessFile]s as
|
||||
* input to the various [parse] methods.
|
||||
*/
|
||||
/// Adds support to the [HtmlParser] for running on a console VM. In particular
|
||||
/// this means it will be able to handle `dart:io` and [RandomAccessFile]s as
|
||||
/// input to the various [parse] methods.
|
||||
void useConsole() {
|
||||
inputstream.consoleSupport = new _ConsoleSupport();
|
||||
}
|
||||
|
@ -26,7 +22,7 @@ class _ConsoleSupport extends inputstream.ConsoleSupport {
|
|||
}
|
||||
|
||||
// TODO(jmesserly): this should be `RandomAccessFile.readAllBytes`.
|
||||
/** Synchronously reads all bytes from the [file]. */
|
||||
/// Synchronously reads all bytes from the [file].
|
||||
List<int> readAllBytesFromFile(RandomAccessFile file) {
|
||||
int length = file.lengthSync();
|
||||
var bytes = new List<int>(length);
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
/** Decodes bytes using the correct name. See [decodeBytes]. */
|
||||
/// Decodes bytes using the correct name. See [decodeBytes].
|
||||
library char_encodings;
|
||||
|
||||
import 'dart:collection';
|
||||
import 'package:utf/utf.dart';
|
||||
|
||||
// TODO(jmesserly): this function is conspicuously absent from dart:utf.
|
||||
/**
|
||||
* Returns true if the [bytes] starts with a UTF-8 byte order mark.
|
||||
* Since UTF-8 doesn't have byte order, it's somewhat of a misnomer, but it is
|
||||
* used in HTML to detect the UTF-
|
||||
*/
|
||||
/// Returns true if the [bytes] starts with a UTF-8 byte order mark.
|
||||
/// Since UTF-8 doesn't have byte order, it's somewhat of a misnomer, but it is
|
||||
/// used in HTML to detect the UTF-
|
||||
bool hasUtf8Bom(List<int> bytes, [int offset = 0, int length]) {
|
||||
int end = length != null ? offset + length : bytes.length;
|
||||
return (offset + 3) <= end &&
|
||||
|
@ -20,11 +18,9 @@ bool hasUtf8Bom(List<int> bytes, [int offset = 0, int length]) {
|
|||
|
||||
// TODO(jmesserly): it's unfortunate that this has to be one-shot on the entire
|
||||
// file, but dart:utf does not expose stream-based decoders yet.
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
/// 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,
|
||||
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
|
||||
|
@ -78,10 +74,8 @@ Iterable<int> decodeBytes(String encoding, List<int> bytes,
|
|||
|
||||
|
||||
// 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.
|
||||
*/
|
||||
/// Returns the code points for the [input]. This works like [String.charCodes]
|
||||
/// but it decodes UTF-16 surrogate pairs.
|
||||
List<int> toCodepoints(String input) {
|
||||
var newCodes = <int>[];
|
||||
for (int i = 0; i < input.length; i++) {
|
||||
|
@ -102,12 +96,10 @@ List<int> toCodepoints(String input) {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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]
|
||||
* rather than replace the bad value.
|
||||
*/
|
||||
/// 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]
|
||||
/// rather than replace the bad value.
|
||||
IterableWindows1252Decoder decodeWindows1252AsIterable(List<int> bytes,
|
||||
[int offset = 0, int length,
|
||||
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
|
||||
|
@ -116,11 +108,9 @@ IterableWindows1252Decoder decodeWindows1252AsIterable(List<int> bytes,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.)
|
||||
*/
|
||||
/// 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.)
|
||||
class IterableWindows1252Decoder extends IterableBase<int> {
|
||||
final List<int> bytes;
|
||||
final int offset;
|
||||
|
@ -136,14 +126,12 @@ class IterableWindows1252Decoder extends IterableBase<int> {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* replacement character. Set the replacementCharacter to null to throw an
|
||||
* ArgumentError rather than replace the bad value. The return value
|
||||
* from this method can be used as an Iterable (e.g. in a for-loop).
|
||||
*/
|
||||
/// 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
|
||||
/// replacement character. Set the replacementCharacter to null to throw an
|
||||
/// ArgumentError rather than replace the bad value. The return value
|
||||
/// from this method can be used as an Iterable (e.g. in a for-loop).
|
||||
class Windows1252Decoder implements Iterator<int> {
|
||||
final int replacementCodepoint;
|
||||
final List<int> _bytes;
|
||||
|
|
|
@ -16,11 +16,9 @@ class ReparseException implements Exception {
|
|||
|
||||
// TODO(jmesserly): assuming the programmatic name is not important, it would be
|
||||
// good to make these "static const" fields on an ErrorMessage class.
|
||||
/**
|
||||
* These are error messages emitted by [HtmlParser]. The values use Python style
|
||||
* string formatting, as implemented by [formatStr]. That function only supports
|
||||
* the subset of format functionality used here.
|
||||
*/
|
||||
/// These are error messages emitted by [HtmlParser]. The values use Python
|
||||
/// style string formatting, as implemented by [formatStr]. That function only
|
||||
/// supports the subset of format functionality used here.
|
||||
const Map<String, String> errorMessages = const {
|
||||
"null-character":
|
||||
"Null character in input stream, replaced with U+FFFD.",
|
||||
|
|
|
@ -6,11 +6,9 @@ import 'inputstream.dart';
|
|||
|
||||
// TODO(jmesserly): I converted StopIteration to StateError("No more elements").
|
||||
// Seems strange to throw this from outside of an iterator though.
|
||||
/**
|
||||
* String-like object with an associated position and various extra methods
|
||||
* If the position is ever greater than the string length then an exception is
|
||||
* raised.
|
||||
*/
|
||||
/// String-like object with an associated position and various extra methods
|
||||
/// If the position is ever greater than the string length then an exception is
|
||||
/// raised.
|
||||
class EncodingBytes extends IterableBase<String> {
|
||||
final String _bytes;
|
||||
int _position = -1;
|
||||
|
@ -62,7 +60,7 @@ class EncodingBytes extends IterableBase<String> {
|
|||
|
||||
String get currentByte => _bytes[position];
|
||||
|
||||
/** Skip past a list of characters. Defaults to skipping [isWhitespace]. */
|
||||
/// 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
|
||||
|
@ -91,11 +89,9 @@ class EncodingBytes extends IterableBase<String> {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a sequence of bytes at the start of a string. If the bytes
|
||||
* are found return true and advance the position to the byte after the
|
||||
* match. Otherwise return false and leave the position alone.
|
||||
*/
|
||||
/// Look for a sequence of bytes at the start of a string. If the bytes
|
||||
/// are found return true and advance the position to the byte after the
|
||||
/// match. Otherwise return false and leave the position alone.
|
||||
bool matchBytes(String bytes) {
|
||||
var p = position;
|
||||
if (_bytes.length < p + bytes.length) {
|
||||
|
@ -109,10 +105,8 @@ class EncodingBytes extends IterableBase<String> {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for the next sequence of bytes matching a given sequence. If
|
||||
* a match is found advance the position to the last byte of the match
|
||||
*/
|
||||
/// Look for the next sequence of bytes matching a given sequence. If
|
||||
/// a match is found advance the position to the last byte of the match
|
||||
bool jumpTo(String bytes) {
|
||||
var newPosition = _bytes.indexOf(bytes, position);
|
||||
if (newPosition >= 0) {
|
||||
|
@ -130,12 +124,12 @@ class EncodingBytes extends IterableBase<String> {
|
|||
}
|
||||
}
|
||||
|
||||
/** Mini parser for detecting character encoding from meta elements. */
|
||||
/// Mini parser for detecting character encoding from meta elements.
|
||||
class EncodingParser {
|
||||
final EncodingBytes data;
|
||||
String encoding;
|
||||
|
||||
/** [bytes] - the data to work on for encoding detection. */
|
||||
/// [bytes] - the data to work on for encoding detection.
|
||||
EncodingParser(List<int> bytes)
|
||||
// Note: this is intentionally interpreting bytes as codepoints.
|
||||
: data = new EncodingBytes(new String.fromCharCodes(bytes).toLowerCase());
|
||||
|
@ -173,7 +167,7 @@ class EncodingParser {
|
|||
return encoding;
|
||||
}
|
||||
|
||||
/** Skip over comments. */
|
||||
/// Skip over comments.
|
||||
bool handleComment() => data.jumpTo("-->");
|
||||
|
||||
bool handleMeta() {
|
||||
|
@ -243,10 +237,8 @@ class EncodingParser {
|
|||
|
||||
bool handleOther() => data.jumpTo(">");
|
||||
|
||||
/**
|
||||
* Return a name,value pair for the next attribute in the stream,
|
||||
* if one is found, or null
|
||||
*/
|
||||
/// Return a name,value pair for the next attribute in the stream,
|
||||
/// if one is found, or null
|
||||
List<String> getAttribute() {
|
||||
// Step 1 (skip chars)
|
||||
var c = data.skipChars((x) => x == "/" || isWhitespace(x));
|
||||
|
|
|
@ -8,7 +8,7 @@ import 'constants.dart';
|
|||
import 'utils.dart';
|
||||
import 'encoding_parser.dart';
|
||||
|
||||
/** Hooks to call into dart:io without directly referencing it. */
|
||||
/// Hooks to call into dart:io without directly referencing it.
|
||||
class ConsoleSupport {
|
||||
List<int> bytesFromFile(source) => null;
|
||||
}
|
||||
|
@ -16,36 +16,32 @@ class ConsoleSupport {
|
|||
// TODO(jmesserly): use lazy init here when supported.
|
||||
ConsoleSupport consoleSupport = new ConsoleSupport();
|
||||
|
||||
/**
|
||||
* Provides a unicode stream of characters to the HtmlTokenizer.
|
||||
*
|
||||
* This class takes care of character encoding and removing or replacing
|
||||
* incorrect byte-sequences and also provides column and line tracking.
|
||||
*/
|
||||
/// Provides a unicode stream of characters to the HtmlTokenizer.
|
||||
///
|
||||
/// This class takes care of character encoding and removing or replacing
|
||||
/// incorrect byte-sequences and also provides column and line tracking.
|
||||
class HtmlInputStream {
|
||||
/**
|
||||
* Number of bytes to use when looking for a meta element with
|
||||
* encoding information.
|
||||
*/
|
||||
/// Number of bytes to use when looking for a meta element with
|
||||
/// encoding information.
|
||||
static const int numBytesMeta = 512;
|
||||
|
||||
/** Encoding to use if no other information can be found. */
|
||||
/// Encoding to use if no other information can be found.
|
||||
static const String defaultEncoding = 'windows-1252';
|
||||
|
||||
/** The name of the character encoding. */
|
||||
/// The name of the character encoding.
|
||||
String charEncodingName;
|
||||
|
||||
/** True if we are certain about [charEncodingName], false for tenative. */
|
||||
/// True if we are certain about [charEncodingName], false for tenative.
|
||||
bool charEncodingCertain = true;
|
||||
|
||||
final bool generateSpans;
|
||||
|
||||
/** Location where the contents of the stream were found. */
|
||||
/// Location where the contents of the stream were found.
|
||||
final String sourceUrl;
|
||||
|
||||
List<int> _rawBytes;
|
||||
|
||||
/** Raw UTF-16 codes, used if a Dart String is passed in. */
|
||||
/// Raw UTF-16 codes, used if a Dart String is passed in.
|
||||
Iterable<int> _rawChars;
|
||||
|
||||
Queue<String> errors;
|
||||
|
@ -58,22 +54,20 @@ class HtmlInputStream {
|
|||
|
||||
int _offset;
|
||||
|
||||
/**
|
||||
* Initialises the HtmlInputStream.
|
||||
*
|
||||
* HtmlInputStream(source, [encoding]) -> Normalized stream from source
|
||||
* for use by html5lib.
|
||||
*
|
||||
* [source] can be either a [String] or a [List<int>] containing the raw
|
||||
* bytes, or a file if [consoleSupport] is initialized.
|
||||
*
|
||||
* The optional encoding parameter must be a string that indicates
|
||||
* the encoding. If specified, that encoding will be used,
|
||||
* regardless of any BOM or later declaration (such as in a meta
|
||||
* element)
|
||||
*
|
||||
* [parseMeta] - Look for a <meta> element containing encoding information
|
||||
*/
|
||||
/// Initialises the HtmlInputStream.
|
||||
///
|
||||
/// HtmlInputStream(source, [encoding]) -> Normalized stream from source
|
||||
/// for use by html5lib.
|
||||
///
|
||||
/// [source] can be either a [String] or a [List<int>] containing the raw
|
||||
/// bytes, or a file if [consoleSupport] is initialized.
|
||||
///
|
||||
/// The optional encoding parameter must be a string that indicates
|
||||
/// the encoding. If specified, that encoding will be used,
|
||||
/// regardless of any BOM or later declaration (such as in a meta
|
||||
/// element)
|
||||
///
|
||||
/// [parseMeta] - Look for a <meta> element containing encoding information
|
||||
HtmlInputStream(source, [String encoding, bool parseMeta = true,
|
||||
this.generateSpans = false, this.sourceUrl])
|
||||
: charEncodingName = codecName(encoding) {
|
||||
|
@ -195,11 +189,9 @@ class HtmlInputStream {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to detect at BOM at the start of the stream. If
|
||||
* an encoding can be determined from the BOM return the name of the
|
||||
* encoding otherwise return null.
|
||||
*/
|
||||
/// Attempts to detect at BOM at the start of the stream. If
|
||||
/// an encoding can be determined from the BOM return the name of the
|
||||
/// encoding otherwise return null.
|
||||
String detectBOM() {
|
||||
// Try detecting the BOM using bytes from the string
|
||||
if (hasUtf8Bom(_rawBytes)) {
|
||||
|
@ -216,7 +208,7 @@ class HtmlInputStream {
|
|||
return null;
|
||||
}
|
||||
|
||||
/** Report the encoding declared by the meta element. */
|
||||
/// Report the encoding declared by the meta element.
|
||||
String detectEncodingMeta() {
|
||||
var parser = new EncodingParser(slice(_rawBytes, 0, numBytesMeta));
|
||||
var encoding = parser.getEncoding();
|
||||
|
@ -228,16 +220,12 @@ class HtmlInputStream {
|
|||
return encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current offset in the stream, i.e. the number of codepoints
|
||||
* since the start of the file.
|
||||
*/
|
||||
/// Returns the current offset in the stream, i.e. the number of codepoints
|
||||
/// since the start of the file.
|
||||
int get position => _offset;
|
||||
|
||||
/**
|
||||
* Read one character from the stream or queue if available. Return
|
||||
* EOF when EOF is reached.
|
||||
*/
|
||||
/// Read one character from the stream or queue if available. Return
|
||||
/// EOF when EOF is reached.
|
||||
String char() {
|
||||
if (_offset >= _chars.length) return EOF;
|
||||
return new String.fromCharCodes([_chars[_offset++]]);
|
||||
|
@ -248,10 +236,8 @@ class HtmlInputStream {
|
|||
return new String.fromCharCodes([_chars[_offset]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string of characters from the stream up to but not
|
||||
* including any character in 'characters' or EOF.
|
||||
*/
|
||||
/// Returns a string of characters from the stream up to but not
|
||||
/// including any character in 'characters' or EOF.
|
||||
String charsUntil(String characters, [bool opposite = false]) {
|
||||
int start = _offset;
|
||||
String c;
|
||||
|
@ -296,10 +282,8 @@ bool invalidUnicode(int c) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the python codec name corresponding to an encoding or null if the
|
||||
* string doesn't correspond to a valid encoding.
|
||||
*/
|
||||
/// Return the python codec name corresponding to an encoding or null if the
|
||||
/// string doesn't correspond to a valid encoding.
|
||||
String codecName(String encoding) {
|
||||
final asciiPunctuation = new RegExp(
|
||||
"[\u0009-\u000D\u0020-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u007E]");
|
||||
|
|
12
pkg/third_party/html5lib/lib/src/list_proxy.dart
vendored
12
pkg/third_party/html5lib/lib/src/list_proxy.dart
vendored
|
@ -1,7 +1,7 @@
|
|||
// TODO(jmesserly): remove this once we have a subclassable growable list
|
||||
// in our libraries.
|
||||
|
||||
/** A [List] proxy that you can subclass. */
|
||||
/// A [List] proxy that you can subclass.
|
||||
library list_proxy;
|
||||
|
||||
import 'dart:collection';
|
||||
|
@ -10,14 +10,12 @@ import 'dart:math' show Random;
|
|||
// TOOD(jmesserly): this needs to be removed, but fixing NodeList is tricky.
|
||||
class ListProxy<E> extends IterableBase<E> implements List<E> {
|
||||
|
||||
/** The inner [List<T>] with the actual storage. */
|
||||
/// The inner [List<T>] with the actual storage.
|
||||
final List<E> _list;
|
||||
|
||||
/**
|
||||
* Creates a list proxy.
|
||||
* You can optionally specify the list to use for [storage] of the items,
|
||||
* otherwise this will create a [List<E>].
|
||||
*/
|
||||
/// 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>[];
|
||||
|
||||
|
|
24
pkg/third_party/html5lib/lib/src/token.dart
vendored
24
pkg/third_party/html5lib/lib/src/token.dart
vendored
|
@ -1,10 +1,10 @@
|
|||
/** This library contains token types used by the html5 tokenizer. */
|
||||
/// This library contains token types used by the html5 tokenizer.
|
||||
library token;
|
||||
|
||||
import 'dart:collection';
|
||||
import 'package:source_maps/span.dart' show FileSpan;
|
||||
|
||||
/** An html5 token. */
|
||||
/// An html5 token.
|
||||
abstract class Token {
|
||||
FileSpan span;
|
||||
|
||||
|
@ -20,18 +20,16 @@ abstract class TagToken extends Token {
|
|||
}
|
||||
|
||||
class StartTagToken extends TagToken {
|
||||
/**
|
||||
* The tag's attributes. A map from the name to the value, where the name
|
||||
* can be a [String] or [AttributeName].
|
||||
*/
|
||||
/// The tag's attributes. A map from the name to the value, where the name
|
||||
/// can be a [String] or [AttributeName].
|
||||
LinkedHashMap<dynamic, String> data;
|
||||
|
||||
/** The attribute spans if requested. Otherwise null. */
|
||||
/// The attribute spans if requested. Otherwise null.
|
||||
List<TagAttribute> attributeSpans;
|
||||
|
||||
bool selfClosingAcknowledged;
|
||||
|
||||
/** The namespace. This is filled in later during tree building. */
|
||||
/// The namespace. This is filled in later during tree building.
|
||||
String namespace;
|
||||
|
||||
StartTagToken(String name, {this.data, bool selfClosing: false,
|
||||
|
@ -54,7 +52,7 @@ abstract class StringToken extends Token {
|
|||
}
|
||||
|
||||
class ParseErrorToken extends StringToken {
|
||||
/** Extra information that goes along with the error message. */
|
||||
/// Extra information that goes along with the error message.
|
||||
Map messageParams;
|
||||
|
||||
ParseErrorToken(String data, {this.messageParams}) : super(data);
|
||||
|
@ -91,11 +89,9 @@ class DoctypeToken extends Token {
|
|||
int get kind => TokenKind.doctype;
|
||||
}
|
||||
|
||||
/**
|
||||
* These are used by the tokenizer to build up the attribute map.
|
||||
* They're also used by [StartTagToken.attributeSpans] if attribute spans are
|
||||
* requested.
|
||||
*/
|
||||
/// These are used by the tokenizer to build up the attribute map.
|
||||
/// They're also used by [StartTagToken.attributeSpans] if attribute spans are
|
||||
/// requested.
|
||||
class TagAttribute {
|
||||
String name;
|
||||
String value;
|
||||
|
|
58
pkg/third_party/html5lib/lib/src/tokenizer.dart
vendored
58
pkg/third_party/html5lib/lib/src/tokenizer.dart
vendored
|
@ -26,9 +26,7 @@ Map<String, List<String>> entitiesByFirstChar = (() {
|
|||
// - use switch instead of the sequential if tests
|
||||
// - avoid string concat
|
||||
|
||||
/**
|
||||
* This class takes care of tokenizing HTML.
|
||||
*/
|
||||
/// This class takes care of tokenizing HTML.
|
||||
class HtmlTokenizer implements Iterator<Token> {
|
||||
// TODO(jmesserly): a lot of these could be made private
|
||||
|
||||
|
@ -38,26 +36,22 @@ class HtmlTokenizer implements Iterator<Token> {
|
|||
|
||||
final bool lowercaseAttrName;
|
||||
|
||||
/** True to generate spans in for [Token.span]. */
|
||||
/// True to generate spans in for [Token.span].
|
||||
final bool generateSpans;
|
||||
|
||||
/** True to generate spans for attributes. */
|
||||
/// True to generate spans for attributes.
|
||||
final bool attributeSpans;
|
||||
|
||||
/**
|
||||
* This reference to the parser is used for correct CDATA handling.
|
||||
* The [HtmlParser] will set this at construction time.
|
||||
*/
|
||||
/// This reference to the parser is used for correct CDATA handling.
|
||||
/// The [HtmlParser] will set this at construction time.
|
||||
HtmlParser parser;
|
||||
|
||||
final Queue<Token> tokenQueue;
|
||||
|
||||
/** Holds the token that is currently being processed. */
|
||||
/// Holds the token that is currently being processed.
|
||||
Token currentToken;
|
||||
|
||||
/**
|
||||
* Holds a reference to the method to be invoked for the next parser state.
|
||||
*/
|
||||
/// Holds a reference to the method to be invoked for the next parser state.
|
||||
// TODO(jmesserly): the type should be "Predicate" but a dart2js checked mode
|
||||
// bug prevents us from doing that. See http://dartbug.com/12465
|
||||
Function state;
|
||||
|
@ -124,13 +118,11 @@ class HtmlTokenizer implements Iterator<Token> {
|
|||
if (attributeSpans) attr.start = stream.position - name.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is where the magic happens.
|
||||
*
|
||||
* We do our usually processing through the states and when we have a token
|
||||
* to return we yield the token which pauses processing until the next token
|
||||
* is requested.
|
||||
*/
|
||||
/// This is where the magic happens.
|
||||
///
|
||||
/// We do our usually processing through the states and when we have a token
|
||||
/// to return we yield the token which pauses processing until the next token
|
||||
/// is requested.
|
||||
bool moveNext() {
|
||||
// Start processing. When EOF is reached state will return false;
|
||||
// instead of true and the loop will terminate.
|
||||
|
@ -149,10 +141,8 @@ class HtmlTokenizer implements Iterator<Token> {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the tokenizer state. Calling this does not reset the [stream] or
|
||||
* the [parser].
|
||||
*/
|
||||
/// Resets the tokenizer state. Calling this does not reset the [stream] or
|
||||
/// the [parser].
|
||||
void reset() {
|
||||
_lastOffset = 0;
|
||||
tokenQueue.clear();
|
||||
|
@ -163,7 +153,7 @@ class HtmlTokenizer implements Iterator<Token> {
|
|||
state = dataState;
|
||||
}
|
||||
|
||||
/** Adds a token to the queue. Sets the span if needed. */
|
||||
/// Adds a token to the queue. Sets the span if needed.
|
||||
void _addToken(Token token) {
|
||||
if (generateSpans && token.span == null) {
|
||||
int offset = stream.position;
|
||||
|
@ -175,11 +165,9 @@ class HtmlTokenizer implements Iterator<Token> {
|
|||
tokenQueue.add(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns either U+FFFD or the character based on the
|
||||
* decimal or hexadecimal representation. It also discards ";" if present.
|
||||
* If not present it will add a [ParseErrorToken].
|
||||
*/
|
||||
/// This function returns either U+FFFD or the character based on the
|
||||
/// decimal or hexadecimal representation. It also discards ";" if present.
|
||||
/// If not present it will add a [ParseErrorToken].
|
||||
String consumeNumberEntity(bool isHex) {
|
||||
var allowed = isDigit;
|
||||
var radix = 10;
|
||||
|
@ -345,16 +333,14 @@ class HtmlTokenizer implements Iterator<Token> {
|
|||
}
|
||||
}
|
||||
|
||||
/** This method replaces the need for "entityInAttributeValueState". */
|
||||
/// This method replaces the need for "entityInAttributeValueState".
|
||||
void processEntityInAttribute(String allowedChar) {
|
||||
consumeEntity(allowedChar: allowedChar, fromAttribute: true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is a generic handler for emitting the tags. It also sets
|
||||
* the state to "data" because that's what's needed after a token has been
|
||||
* emitted.
|
||||
*/
|
||||
/// This method is a generic handler for emitting the tags. It also sets
|
||||
/// the state to "data" because that's what's needed after a token has been
|
||||
/// emitted.
|
||||
void emitCurrentToken() {
|
||||
var token = currentToken;
|
||||
// Add token to the queue to be yielded
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/** Internals to the tree builders. */
|
||||
/// Internals to the tree builders.
|
||||
library treebuilder;
|
||||
|
||||
import 'dart:collection';
|
||||
|
@ -66,7 +66,7 @@ bool _nodesEqual(Node node1, Node node2) {
|
|||
_mapEquals(node1.attributes, node2.attributes);
|
||||
}
|
||||
|
||||
/** Basic treebuilder implementation. */
|
||||
/// Basic treebuilder implementation.
|
||||
class TreeBuilder {
|
||||
final String defaultNamespace;
|
||||
|
||||
|
@ -80,10 +80,8 @@ class TreeBuilder {
|
|||
|
||||
Node formPointer;
|
||||
|
||||
/**
|
||||
* Switch the function used to insert an element from the
|
||||
* normal one to the misnested table one and back again
|
||||
*/
|
||||
/// Switch the function used to insert an element from the
|
||||
/// normal one to the misnested table one and back again
|
||||
bool insertFromTable;
|
||||
|
||||
TreeBuilder(bool namespaceHTMLElements)
|
||||
|
@ -212,11 +210,9 @@ class TreeBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an element exists between the end of the active
|
||||
* formatting elements and the last marker. If it does, return it, else
|
||||
* return null.
|
||||
*/
|
||||
/// Check if an element exists between the end of the active
|
||||
/// formatting elements and the last marker. If it does, return it, else
|
||||
/// return null.
|
||||
Node elementInActiveFormattingElements(String name) {
|
||||
for (Node item in activeFormattingElements.reversed) {
|
||||
// Check for Marker first because if it's a Marker it doesn't have a
|
||||
|
@ -249,7 +245,7 @@ class TreeBuilder {
|
|||
parent.nodes.add(new Comment(token.data)..sourceSpan = token.span);
|
||||
}
|
||||
|
||||
/** Create an element but don't insert it anywhere */
|
||||
/// Create an element but don't insert it anywhere
|
||||
Element createElement(StartTagToken token) {
|
||||
var name = token.name;
|
||||
var namespace = token.namespace;
|
||||
|
@ -278,7 +274,7 @@ class TreeBuilder {
|
|||
}
|
||||
|
||||
Element insertElementTable(token) {
|
||||
/** Create an element and insert it into the tree */
|
||||
/// Create an element and insert it into the tree
|
||||
var element = createElement(token);
|
||||
if (!tableInsertModeElements.contains(openElements.last.tagName)) {
|
||||
return insertElementNormal(token);
|
||||
|
@ -299,7 +295,7 @@ class TreeBuilder {
|
|||
return element;
|
||||
}
|
||||
|
||||
/** Insert text data. */
|
||||
/// Insert text data.
|
||||
void insertText(String data, FileSpan span) {
|
||||
var parent = openElements.last;
|
||||
|
||||
|
@ -314,10 +310,8 @@ class TreeBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert [data] as text in the current node, positioned before the
|
||||
* start of node [refNode] or to the end of the node's text.
|
||||
*/
|
||||
/// Insert [data] as text in the current node, positioned before the
|
||||
/// start of node [refNode] or to the end of the node's text.
|
||||
static void _insertText(Node parent, String data, FileSpan span,
|
||||
[Element refNode]) {
|
||||
var nodes = parent.nodes;
|
||||
|
@ -344,10 +338,8 @@ class TreeBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the foster parent element, and sibling to insert before
|
||||
* (or null) when inserting a misnested table node
|
||||
*/
|
||||
/// Get the foster parent element, and sibling to insert before
|
||||
/// (or null) when inserting a misnested table node
|
||||
List<Node> getTableMisnestedNodePosition() {
|
||||
// The foster parent element is the one which comes before the most
|
||||
// recently opened table element
|
||||
|
@ -388,10 +380,10 @@ class TreeBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/** Return the final tree. */
|
||||
/// Return the final tree.
|
||||
Document getDocument() => document;
|
||||
|
||||
/** Return the final fragment. */
|
||||
/// Return the final fragment.
|
||||
DocumentFragment getFragment() {
|
||||
//XXX assert innerHTML
|
||||
var fragment = new DocumentFragment();
|
||||
|
|
10
pkg/third_party/html5lib/lib/src/utils.dart
vendored
10
pkg/third_party/html5lib/lib/src/utils.dart
vendored
|
@ -1,4 +1,4 @@
|
|||
/** Misc things that were useful when porting the code from Python. */
|
||||
/// Misc things that were useful when porting the code from Python.
|
||||
library utils;
|
||||
|
||||
import 'constants.dart';
|
||||
|
@ -71,11 +71,9 @@ String padWithZeros(String str, int size) {
|
|||
|
||||
// TODO(jmesserly): this implementation is pretty wrong, but I need something
|
||||
// quick until dartbug.com/1694 is fixed.
|
||||
/**
|
||||
* Format a string like Python's % string format operator. Right now this only
|
||||
* supports a [data] dictionary used with %s or %08x. Those were the only things
|
||||
* needed for [errorMessages].
|
||||
*/
|
||||
/// Format a string like Python's % string format operator. Right now this only
|
||||
/// supports a [data] dictionary used with %s or %08x. Those were the only
|
||||
/// things needed for [errorMessages].
|
||||
String formatStr(String format, Map data) {
|
||||
if (data == null) return format;
|
||||
data.forEach((key, value) {
|
||||
|
|
2
pkg/third_party/html5lib/test/dom_test.dart
vendored
2
pkg/third_party/html5lib/test/dom_test.dart
vendored
|
@ -1,4 +1,4 @@
|
|||
/** Additional feature tests that aren't based on test data. */
|
||||
/// Additional feature tests that aren't based on test data.
|
||||
library dom_test;
|
||||
|
||||
import 'package:unittest/unittest.dart';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/** Additional feature tests that aren't based on test data. */
|
||||
/// Additional feature tests that aren't based on test data.
|
||||
library parser_feature_test;
|
||||
|
||||
import 'package:unittest/unittest.dart';
|
||||
|
|
|
@ -109,7 +109,7 @@ void main() {
|
|||
}
|
||||
}
|
||||
|
||||
/** Extract the name for the test based on the test input data. */
|
||||
/// Extract the name for the test based on the test input data.
|
||||
_nameFor(String input) {
|
||||
// Using JSON.decode to unescape other unicode characters
|
||||
var escapeQuote = input
|
||||
|
|
14
pkg/third_party/html5lib/test/support.dart
vendored
14
pkg/third_party/html5lib/test/support.dart
vendored
|
@ -1,4 +1,4 @@
|
|||
/** Support code for the tests in this directory. */
|
||||
/// Support code for the tests in this directory.
|
||||
library support;
|
||||
|
||||
import 'dart:io';
|
||||
|
@ -72,10 +72,8 @@ class TestData extends IterableBase<Map> {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current heading is a test section heading return the heading,
|
||||
* otherwise return null.
|
||||
*/
|
||||
/// If the current heading is a test section heading return the heading,
|
||||
/// otherwise return null.
|
||||
static String sectionHeading(String line) {
|
||||
return line.startsWith("#") ? line.substring(1).trim() : null;
|
||||
}
|
||||
|
@ -91,14 +89,12 @@ class TestData extends IterableBase<Map> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the [document] into the html5 test data format.
|
||||
*/
|
||||
/// Serialize the [document] into the html5 test data format.
|
||||
testSerializer(Document document) {
|
||||
return (new TestSerializer()..visit(document)).toString();
|
||||
}
|
||||
|
||||
/** Serializes the DOM into test format. See [testSerializer]. */
|
||||
/// Serializes the DOM into test format. See [testSerializer].
|
||||
class TestSerializer extends TreeVisitor {
|
||||
final StringBuffer _str;
|
||||
int _indent = 0;
|
||||
|
|
|
@ -134,12 +134,10 @@ List normalizeTokens(List 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.
|
||||
*/
|
||||
/// 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]) {
|
||||
|
||||
|
|
|
@ -33,18 +33,21 @@ main(List<String> args) {
|
|||
|
||||
void fixFile(String path) {
|
||||
var file = new File(path);
|
||||
file.readAsLines().then(fixContents).then((fixed) {
|
||||
file.readAsLines().then((lines) => fixContents(lines, path)).then((fixed) {
|
||||
return new File(path).writeAsString(fixed);
|
||||
}).then((file) {
|
||||
print(file.path);
|
||||
});
|
||||
}
|
||||
|
||||
String fixContents(List<String> lines) {
|
||||
String fixContents(List<String> lines, String path) {
|
||||
var buffer = new StringBuffer();
|
||||
var linesOut = 0;
|
||||
var inBlock = false;
|
||||
var indent;
|
||||
|
||||
for (var line in lines) {
|
||||
var oldLine = line;
|
||||
if (inBlock) {
|
||||
// See if it's the end of the comment.
|
||||
if (endBlock.hasMatch(line)) {
|
||||
|
@ -92,7 +95,21 @@ String fixContents(List<String> lines) {
|
|||
}
|
||||
}
|
||||
|
||||
if (line != null) buffer.write('$line\n');
|
||||
if (line != null) {
|
||||
linesOut++;
|
||||
|
||||
// Warn about lines that crossed 80 columns as a result of the change.
|
||||
if (line.length > 80 && oldLine.length <= 80) {
|
||||
const _PURPLE = '\u001b[35m';
|
||||
const _RED = '\u001b[31m';
|
||||
const _NO_COLOR = '\u001b[0m';
|
||||
|
||||
print('$_PURPLE$path$_NO_COLOR:$_RED$linesOut$_NO_COLOR: '
|
||||
'line exceeds 80 cols:\n $line');
|
||||
}
|
||||
|
||||
buffer.write('$line\n');
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
|
|
Loading…
Reference in a new issue