-
Notifications
You must be signed in to change notification settings - Fork 44
/
base.scala
207 lines (167 loc) · 7.01 KB
/
base.scala
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package laika.ast
import laika.parse.SourceFragment
/** The base class for all Elements forming the document tree.
* Usually not extended directly, instead either `Span` or `Block` should be picked as the base type
* for new element types.
*
* All node types have an optional id and zero or more associated styles serving as render hints.
*/
abstract class Element extends Product with Serializable {
type Self <: Element
def options: Options
/** Indicates whether this element has the specified style assigned.
*/
def hasStyle(name: String): Boolean = options.styles.contains(name)
/** Indicates whether this element has an id assigned.
*/
def hasId: Boolean = options.id.isDefined
/** Returns a new instance of this element without its id.
*/
def withoutId: Self = modifyOptions(opt => Options(None, opt.styles))
/** Returns a new instance of this element with its id set to the specified value, overriding any existing value.
*/
def withId(id: String): Self = modifyOptions(opt => Options(Some(id), opt.styles))
/** Returns a new instance of this element with the specified style added to its existing styles.
*/
def withStyle(name: String): Self = mergeOptions(Styles(name))
/** Returns a new instance of this element with the specified styles added to its existing styles.
*/
def withStyles(style: String, styles: String*): Self = mergeOptions(
Styles((style +: styles).toSet)
)
/** Returns a new instance of this element with the specified styles added to its existing styles.
*/
def withStyles(styles: Iterable[String]): Self = mergeOptions(Styles(styles.toSet))
/** Returns a new instance of this element with its options merged with the specified options.
*/
def mergeOptions(opt: Options): Self = modifyOptions(_ + opt)
/** Returns a new instance of this element with the new options obtained from applying the specified function
* to the existing value.
*/
def modifyOptions(f: Options => Options): Self = withOptions(f(options))
/** Returns a new instance of this element with all options removed from it.
*/
def clearOptions: Self = withOptions(Options.empty)
/** Returns a new instance of this element with the specified options replacing the current value.
*/
def withOptions(options: Options): Self
}
/** Provides a fallback for elements the renderer does not know how to deal with.
*/
trait Fallback {
/** Defines a fallback for this element in case the renderer does not know how to deal with it.
*/
def fallback: Element
}
/** The base type for all block level elements.
*/
trait Block extends Element { type Self <: Block }
/** The base type for all inline elements.
*/
trait Span extends Element { type Self <: Span }
/** The base type for all list items.
*/
trait ListItem extends Element { type Self <: ListItem }
/** Represents a hidden element that will be ignored by renderers.
*
* These kind of nodes usually provide information that will be extracted
* from the tree before AST transformations and renderers get applied.
*/
trait Hidden extends Element
/** Represents an element that needs to be resolved in an AST transformation step.
*
* Passing documents that still contain elements of this kind to a renderer
* will usually be treated as errors.
*/
trait Unresolved extends Element {
/** The fragment from the input source that produced this element.
* Can be used to report the line of the error or to render a fallback that simply renders back
* the consumed input.
*/
def source: SourceFragment
/** An error message to display when this element remains unresolved until after the final AST transformation step.
*/
def unresolvedMessage: String
}
/** Represents an invalid element.
* Renderers can choose to either render the fallback or the runtime message or both,
* depending on the configuration of the transformer or renderer.
*/
trait Invalid extends Element with Fallback {
type FallbackElement <: Element
/** The fragment from the input source that produced this element.
* Can be used to report the line of the error or to render a fallback that simply renders back
* the consumed input.
*/
def source: SourceFragment
/** A message describing the reason why this element is invalid.
*/
def message: RuntimeMessage
/** A fallback that can be used in case a transformer or renderer is configured in such a way that
* errors are ignored.
* Renderers will pick this fallback element instead of the original invalid element in such a case.
*/
def fallback: FallbackElement
}
/** The base type for all reference elements.
*
* A reference points to some other node in the document tree and needs
* to be resolved and replaced by a rewrite rule before rendering.
* Therefore none of the available renderers include logic for dealing with references.
*/
trait Reference extends Span with Unresolved {
type Self <: Reference
}
/** Represents a definition that can be used to resolve references.
*
* Only part of the raw document tree and then removed or replaced
* by a rewrite rule before rendering.
*/
trait Definition extends Block { type Self <: Definition }
/** The base type for all link elements.
*
* In contrast to the reference type, it is only mixed in by elements representing resolved links
* that can be dealt with by renderers.
*/
sealed trait Link extends Span { type Self <: Link }
/** A local link that always points to a target within the same document.
*/
trait LocalLink extends Link {
type Self <: LocalLink
/** The id of the node within the same document that this link points to. */
def refId: String
}
/** A global link that can point to any document within the input tree or to an external target.
*/
trait GlobalLink extends Link {
type Self <: GlobalLink
/** The target this link points to. */
def target: Target
/** Creates a new instance of this node pointing to the specified target instead.
*/
def withTarget(target: Target): Self
/** Indicates whether this node type supports external targets for *all* output formats.
* This is not true for images, for example, as they require embedding for EPUB and PDF formats.
*/
def supportsExternalTargets: Boolean
}
/** The base type for all link targets. The id has to be
* unique for the whole document across all types
* of `LinkTarget` implementations.
*/
trait LinkTarget extends Block { type Self <: LinkTarget }