1+ //
2+ // Copyright (c) 2024, Brian Frank and Andy Frank
3+ // Licensed under the Academic Free License version 3.0
4+ //
5+ // History:
6+ // 08 Oct 2024 Matthew Giannini Creation
7+ //
8+
9+ **
10+ ** A block node.
11+ **
12+ ** We can think of a document as a sequence of blocks - structural
13+ ** elements like paragraphs, block quotations, lists, headings, rules,
14+ ** and code blocks. Some blocks contain other blocks; others contain
15+ ** inline content (text, images, code spans, etc.).
16+ **
17+ @Js
18+ abstract class Block : Node
19+ {
20+ override Block? parent() { super .parent }
21+
22+ protected override Void setParent(Node? p)
23+ {
24+ if (p isnot Block)
25+ throw ArgErr("Parent of block must also be a block" )
26+ super .setParent(p)
27+ }
28+ }
29+
30+ **************************************************************************
31+ ** Document
32+ **************************************************************************
33+
34+ ** Document is the root node of the AST
35+ @Js
36+ final class Document : Block { }
37+
38+ **************************************************************************
39+ ** Heading
40+ **************************************************************************
41+
42+ ** Heading block
43+ @Js
44+ class Heading : Block
45+ {
46+ new make(Int level := 0 ) { this .level = level }
47+
48+ ** The heading "level"
49+ const Int level
50+ }
51+
52+ **************************************************************************
53+ ** BlockQuote
54+ **************************************************************************
55+
56+ ** Block quote block
57+ @Js
58+ class BlockQuote : Block { }
59+
60+ **************************************************************************
61+ ** FencedCode
62+ **************************************************************************
63+
64+ ** Fenced code block
65+ @Js
66+ class FencedCode : Block
67+ {
68+ new make(Str ? fenceChar := null )
69+ {
70+ this .fenceChar = fenceChar
71+ }
72+
73+ ** The fence character that was used, e.g. '`', or '~', if available, or null otherwise
74+ Str ? fenceChar
75+
76+ Int fenceIndent := 0
77+
78+ ** The length of the opening fence (how many of the `fenceChar` were used to start
79+ ** the code block) if available, or null otherwise
80+ Int ? openingFenceLen
81+ {
82+ set {
83+ if (it != null && it < 3 ) throw ArgErr("openingFenceLen needs to be >= 3" )
84+ checkFenceLens(it , closingFenceLen)
85+ &openingFenceLen = it
86+ }
87+ }
88+
89+ ** The length of the closing fence (how many of the `fenceChar` were used to end
90+ ** the code block) if available, or null otherwise
91+ Int ? closingFenceLen
92+ {
93+ set {
94+ if (it != null && it < 3 ) throw ArgErr("closingFenceLen needs to be >= 3" )
95+ checkFenceLens(openingFenceLen, it )
96+ &closingFenceLen = it
97+ }
98+ }
99+
100+ ** Optional info string (see spec), e.g. 'fantom' in '```fantom'
101+ Str ? info
102+
103+ Str ? literal
104+
105+ private static Void checkFenceLens(Int ? openingFenceLen, Int ? closingFenceLen)
106+ {
107+ if (openingFenceLen != null && closingFenceLen != null )
108+ {
109+ if (closingFenceLen < openingFenceLen)
110+ throw ArgErr("fence lengths required to be: closingFenceLen >= openingFenceLen" )
111+ }
112+ }
113+ }
114+
115+ **************************************************************************
116+ ** HtmlBlock
117+ **************************************************************************
118+
119+ ** HTML block
120+ @Js
121+ class HtmlBlock : Block
122+ {
123+ new make(Str ? literal := null ) { this .literal = literal }
124+
125+ Str ? literal
126+ }
127+
128+ **************************************************************************
129+ ** ThematicBreak
130+ **************************************************************************
131+
132+ ** Thematic break block
133+ @Js
134+ class ThematicBreak : Block
135+ {
136+ new make(Str ? literal := null ) { this .literal = literal }
137+
138+ ** source literal that represents this break, if available
139+ Str ? literal
140+ }
141+
142+ **************************************************************************
143+ ** IndentedCode
144+ **************************************************************************
145+
146+ ** Indented code block
147+ @Js
148+ class IndentedCode : Block
149+ {
150+ new make(Str ? literal := null ) { this .literal = literal }
151+
152+ ** Indented code literal
153+ Str ? literal
154+ }
155+
156+ ** Abstract base class for list blocks
157+ @Js
158+ abstract class ListBlock : Block
159+ {
160+ ** Whether this list is tight or loose
161+ **
162+ ** spec: A list is loose if any of its constituent list items are separated by blank
163+ ** lines, or if any of its constituent list items directly contain two block-level
164+ ** elements with a blank line between them. Otherwise, a list is tight.
165+ ** (The difference in HTML output is that paragraphs in a loose list are
166+ ** wrapped in <p> tags, while paragraphs in a tight list are not.)
167+ Bool tight := false
168+ }
169+
170+ **************************************************************************
171+ ** BulletList
172+ **************************************************************************
173+
174+ ** Bullet list block
175+ @Js
176+ class BulletList : ListBlock
177+ {
178+ new make(Str ? marker := null ) { this .marker = marker }
179+
180+ ** The bullet list marker that was used, e.g. '-', '*', or '+', if available,
181+ ** or null otherwise.
182+ Str ? marker
183+ }
184+
185+ **************************************************************************
186+ ** OrderedList
187+ **************************************************************************
188+
189+ ** Ordered list block
190+ @Js
191+ class OrderedList : ListBlock
192+ {
193+ new make(Int ? startNumber, Str ? markerDelim)
194+ {
195+ this .startNumber = startNumber
196+ this .markerDelim = markerDelim
197+ }
198+
199+ ** The start number used in the marker, e.g. '1', if available, or null otherwise
200+ Int ? startNumber
201+
202+ ** The delimiter used in the marker, e.g. '.' or ')', if available, or null otherwise
203+ Str ? markerDelim
204+ }
205+
206+ **************************************************************************
207+ ** ListItem
208+ **************************************************************************
209+
210+ ** List item
211+ @Js
212+ class ListItem : Block
213+ {
214+ new make(Int ? markerIndent, Int ? contentIndent)
215+ {
216+ this .markerIndent = markerIndent
217+ this .contentIndent = contentIndent
218+ }
219+
220+ ** The indent of the marker such as '-' or '1.' in columns (spaces or tab stop of 4)
221+ ** if available, or null otherwise.
222+ **
223+ ** - '- Foo' (marker indent: 0)
224+ ** - ' - Foo' (marker indent: 1)
225+ ** - ' 1. Foo' (marker indent: 2)
226+ Int ? markerIndent
227+
228+ ** The indent of the content in columns (spaces or tab stop of 4) if available
229+ ** or null otherwise. The content indent is counted from the beginning of the line
230+ ** and includes the marker on the first line
231+ **
232+ ** - '- Foo' (content indent: 2)
233+ ** - ' - Foo' (content indent: 3)
234+ ** - ' 1. Foo' (content indent: 5)
235+ **
236+ ** Note that subsequent lines in the same list item need to be indented by at least
237+ ** the content indent to be counted as part of the list item.
238+ Int ? contentIndent
239+ }
240+
241+ **************************************************************************
242+ ** Paragraph
243+ **************************************************************************
244+
245+ ** Paragraph
246+ @Js
247+ class Paragraph : Block { }
248+
249+ **************************************************************************
250+ ** CustomBlock
251+ **************************************************************************
252+
253+ ** Custom Block
254+ @Js
255+ abstract class CustomBlock : Block { }
0 commit comments