-
Notifications
You must be signed in to change notification settings - Fork 362
/
Copy pathnode.dart
91 lines (75 loc) · 2.87 KB
/
node.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// Copyright 2019 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'dart:collection';
import '../../../visitor/interface/modifiable_css.dart';
import '../node.dart';
/// A modifiable version of [CssNode].
///
/// Almost all CSS nodes are the modifiable classes under the covers. However,
/// modification should only be done within the evaluation step, so the
/// unmodifiable types are used elsewhere to enforce that constraint.
abstract base class ModifiableCssNode extends CssNode {
ModifiableCssParentNode? get parent => _parent;
ModifiableCssParentNode? _parent;
/// The index of `this` in `parent.children`.
///
/// This makes [remove] more efficient.
int? _indexInParent;
var isGroupEnd = false;
/// Whether this node has a visible sibling after it.
bool get hasFollowingSibling =>
_parent?.children
.skip(_indexInParent! + 1)
.any((sibling) => !sibling.isInvisible) ??
false;
T accept<T>(ModifiableCssVisitor<T> visitor);
/// Removes `this` from [parent]'s child list.
///
/// Throws a [StateError] if [parent] is `null`.
void remove() {
var parent = _parent;
if (parent == null) {
throw StateError("Can't remove a node without a parent.");
}
parent._children.removeAt(_indexInParent!);
for (var child in parent._children.skip(_indexInParent!)) {
child._indexInParent = child._indexInParent! - 1;
}
_parent = null;
}
}
/// A modifiable version of [CssParentNode] for use in the evaluation step.
abstract base class ModifiableCssParentNode extends ModifiableCssNode
implements CssParentNode {
final List<ModifiableCssNode> children;
final List<ModifiableCssNode> _children;
bool get isChildless => false;
ModifiableCssParentNode() : this._([]);
/// A dummy constructor so that [_children] can be passed to the constructor
/// for [this.children].
ModifiableCssParentNode._(List<ModifiableCssNode> children)
: _children = children,
children = UnmodifiableListView(children);
/// Returns whether `this` is equal to [other], ignoring their child nodes.
bool equalsIgnoringChildren(ModifiableCssNode other);
/// Returns a copy of `this` with an empty [children] list.
///
/// This is *not* a deep copy. If other parts of this node are modifiable,
/// they are shared between the new and old nodes.
ModifiableCssParentNode copyWithoutChildren();
/// Adds [child] as a child of this statement.
void addChild(ModifiableCssNode child) {
child._parent = this;
child._indexInParent = _children.length;
_children.add(child);
}
/// Destructively removes all elements from [children].
void clearChildren() {
for (var child in _children) {
child._parent = null;
child._indexInParent = null;
}
_children.clear();
}
}