-
Notifications
You must be signed in to change notification settings - Fork 44
/
ParserBundle.scala
121 lines (111 loc) · 5.31 KB
/
ParserBundle.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
/*
* 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.api.bundle
import laika.ast.*
import laika.ast.styles.StyleDeclaration
import laika.parse.Parser
/** Bundles a collection of all types of parsers used in a transformation.
*
* The parsers for text markup and configuration headers are meant to complement
* base parsers defined by the host language. If they fail for a given input the built-in parsers
* will still be tried for the same block, span or configuration header respectively.
*
* The parsers for stylesheets and templates on the other hand are meant to overwrite
* any previously installed parsers.
*
* @param blockParsers parsers for block elements in text markup, complementing the parsers of the host language
* @param spanParsers parsers for span elements in text markup, complementing the parsers of the host language
* @param syntaxHighlighters parsers for syntax highlighting of code blocks
* @param markupParserHooks hooks for markup parsers to control aspects beyond the individual span and block parsers
* @param configProvider parser for configuration headers in text markup and template documents and configuration documents
* @param templateParser parser for template documents
* @param styleSheetParser parser for CSS documents
*/
class ParserBundle(
val blockParsers: Seq[BlockParserBuilder] = Nil,
val spanParsers: Seq[SpanParserBuilder] = Nil,
val syntaxHighlighters: Seq[SyntaxHighlighter] = Nil,
val markupParserHooks: Option[ParserHooks] = None,
val configProvider: Option[ConfigProvider] = None,
val templateParser: Option[Parser[TemplateRoot]] = None,
val styleSheetParser: Option[Parser[Set[StyleDeclaration]]] = None
) {
/** Merges this instance with the specified base.
* Collections of parsers will be merged.
* Optional parsers in this instance will overwrite optional parsers
* in the base (if defined), with the base only serving as a fallback.
*/
def withBase(base: ParserBundle): ParserBundle =
new ParserBundle(
blockParsers ++ base.blockParsers,
spanParsers ++ base.spanParsers,
syntaxHighlighters ++ base.syntaxHighlighters,
(markupParserHooks.toSeq ++ base.markupParserHooks.toSeq).reduceLeftOption(_ withBase _),
configProvider.orElse(base.configProvider),
templateParser.orElse(base.templateParser),
styleSheetParser.orElse(base.styleSheetParser)
)
/** Just the extensions for the text markup parser defined in this bundle.
* Fallback instances will be added where appropriate for parsers or hooks not defined
* in this bundle.
*/
private[laika] def markupExtensions: MarkupExtensions =
new MarkupExtensions(
blockParsers,
spanParsers,
syntaxHighlighters,
markupParserHooks.getOrElse(new ParserHooks())
)
}
/** Hooks for markup parsers to control aspects beyond the individual span and block
* parsers defined for the host language.
*
* @param postProcessBlocks function invoked for every block container, allowing post-processing of the result
* @param postProcessDocument function invoked after parsing but before rewriting, allowing to modify the document
* @param preProcessInput function invoked before parsing, allowing to pre-process the input
*/
class ParserHooks(
val postProcessBlocks: Seq[Block] => Seq[Block] = identity,
val postProcessDocument: UnresolvedDocument => UnresolvedDocument = identity,
val preProcessInput: String => String = identity
) {
/** Merges this instance with the specified base.
* The functions specified in the base are always invoked before
* the functions in this instance.
*/
def withBase(base: ParserHooks): ParserHooks = new ParserHooks(
base.postProcessBlocks andThen postProcessBlocks,
base.postProcessDocument andThen postProcessDocument,
base.preProcessInput andThen preProcessInput
)
}
/** Bundles extensions for the text markup parsers defined for the host language to support additional
* syntax not recognized by the base parsers.
*
* When extension parsers fail for a given input the built-in parsers
* will still be tried for the same block or span respectively.
*
* @param blockParsers parsers for block elements in text markup, complementing the parsers of the host language
* @param spanParsers parsers for span elements in text markup, complementing the parsers of the host language
* @param syntaxHighlighters parsers for syntax highlighting of code blocks
* @param parserHooks hooks for markup parsers to control aspects beyond the individual span and block parsers
*/
private[laika] class MarkupExtensions(
val blockParsers: Seq[BlockParserBuilder],
val spanParsers: Seq[SpanParserBuilder],
val syntaxHighlighters: Seq[SyntaxHighlighter],
val parserHooks: ParserHooks
)