coradoc-adoc 2.0.22 → 2.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/coradoc/asciidoc/model/attribute_list.rb +31 -4
- data/lib/coradoc/asciidoc/model/base.rb +7 -0
- data/lib/coradoc/asciidoc/model/image/attribute_extractor.rb +142 -0
- data/lib/coradoc/asciidoc/model/image/block_image.rb +8 -0
- data/lib/coradoc/asciidoc/model/image/core.rb +35 -26
- data/lib/coradoc/asciidoc/model/image/inline_image.rb +7 -0
- data/lib/coradoc/asciidoc/model/image.rb +1 -0
- data/lib/coradoc/asciidoc/parser/attribute_list.rb +4 -1
- data/lib/coradoc/asciidoc/serializer/serializers/image/core.rb +3 -1
- data/lib/coradoc/asciidoc/transform/element_transformers/admonition_styles.rb +6 -1
- data/lib/coradoc/asciidoc/transform/element_transformers/block_transformer.rb +39 -16
- data/lib/coradoc/asciidoc/transform/element_transformers/document_transformer.rb +2 -27
- data/lib/coradoc/asciidoc/transform/element_transformers/include_transformer.rb +2 -1
- data/lib/coradoc/asciidoc/transform/element_transformers/inline_transformer.rb +12 -6
- data/lib/coradoc/asciidoc/transform/element_transformers/list_transformer.rb +10 -4
- data/lib/coradoc/asciidoc/transform/element_transformers/other_transformer.rb +25 -22
- data/lib/coradoc/asciidoc/transform/element_transformers/table_transformer.rb +6 -3
- data/lib/coradoc/asciidoc/transform/from_core_model.rb +16 -40
- data/lib/coradoc/asciidoc/transform/inline_transform_visitor.rb +23 -5
- data/lib/coradoc/asciidoc/transform/to_core_model.rb +30 -6
- data/lib/coradoc/asciidoc/transformer/block_rules.rb +19 -5
- data/lib/coradoc/asciidoc/transformer/header_rules.rb +12 -3
- data/lib/coradoc/asciidoc/transformer/inline_rules.rb +68 -20
- data/lib/coradoc/asciidoc/transformer/list_rules.rb +20 -5
- data/lib/coradoc/asciidoc/transformer/misc_rules.rb +31 -12
- data/lib/coradoc/asciidoc/transformer/source_line_extractor.rb +67 -0
- data/lib/coradoc/asciidoc/transformer/structural_rules.rb +7 -3
- data/lib/coradoc/asciidoc/transformer/text_rules.rb +33 -9
- data/lib/coradoc/asciidoc/transformer.rb +6 -1
- data/lib/coradoc/asciidoc/version.rb +1 -1
- metadata +3 -1
|
@@ -16,11 +16,15 @@ module Coradoc
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
if marker_type == 'definition'
|
|
19
|
-
Coradoc::CoreModel::DefinitionList.new(
|
|
19
|
+
Coradoc::CoreModel::DefinitionList.new(
|
|
20
|
+
items: items,
|
|
21
|
+
source_line: list.source_line
|
|
22
|
+
)
|
|
20
23
|
else
|
|
21
24
|
Coradoc::CoreModel::ListBlock.new(
|
|
22
25
|
marker_type: marker_type,
|
|
23
|
-
items: items
|
|
26
|
+
items: items,
|
|
27
|
+
source_line: list.source_line
|
|
24
28
|
)
|
|
25
29
|
end
|
|
26
30
|
end
|
|
@@ -45,7 +49,8 @@ module Coradoc
|
|
|
45
49
|
term: ToCoreModel.extract_text_content(term_children),
|
|
46
50
|
definitions: [ToCoreModel.extract_text_content(def_children)],
|
|
47
51
|
term_children: term_children,
|
|
48
|
-
definition_children: def_children
|
|
52
|
+
definition_children: def_children,
|
|
53
|
+
source_line: item.source_line
|
|
49
54
|
)
|
|
50
55
|
di.id = item.id if item.id
|
|
51
56
|
|
|
@@ -63,7 +68,8 @@ module Coradoc
|
|
|
63
68
|
|
|
64
69
|
li = Coradoc::CoreModel::ListItem.new(
|
|
65
70
|
content: ToCoreModel.extract_text_content(content_val),
|
|
66
|
-
marker: item.marker
|
|
71
|
+
marker: item.marker,
|
|
72
|
+
source_line: item.source_line
|
|
67
73
|
)
|
|
68
74
|
li.children = children
|
|
69
75
|
|
|
@@ -10,7 +10,8 @@ module Coradoc
|
|
|
10
10
|
Coradoc::CoreModel::Term.new(
|
|
11
11
|
text: term.term.to_s,
|
|
12
12
|
type: term.type&.to_s || 'preferred',
|
|
13
|
-
lang: term.lang&.to_s || 'en'
|
|
13
|
+
lang: term.lang&.to_s || 'en',
|
|
14
|
+
source_line: term.source_line
|
|
14
15
|
)
|
|
15
16
|
end
|
|
16
17
|
|
|
@@ -19,31 +20,31 @@ module Coradoc
|
|
|
19
20
|
children = ToCoreModel.transform_inline_content(admonition.content)
|
|
20
21
|
block = Coradoc::CoreModel::AnnotationBlock.new(
|
|
21
22
|
annotation_type: canonical,
|
|
22
|
-
content: ToCoreModel.extract_text_content(admonition.content)
|
|
23
|
+
content: ToCoreModel.extract_text_content(admonition.content),
|
|
24
|
+
source_line: admonition.source_line
|
|
23
25
|
)
|
|
24
26
|
block.children = children
|
|
25
27
|
block
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
def transform_image(image)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
)
|
|
31
|
+
Coradoc::CoreModel::Image.new(**image_attributes(image))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def image_attributes(image)
|
|
35
|
+
{
|
|
36
|
+
src: normalize_image_src(image.src),
|
|
37
|
+
alt: image.alt, title: image.title, caption: image.caption,
|
|
38
|
+
width: image.width, height: image.height,
|
|
39
|
+
link: image.link, role: image.role,
|
|
40
|
+
inline: image.is_a?(Coradoc::AsciiDoc::Model::Image::InlineImage),
|
|
41
|
+
source_line: image.source_line
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def normalize_image_src(src)
|
|
46
|
+
s = src.to_s
|
|
47
|
+
s.start_with?(':') ? s[1..] : s
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
def transform_bibliography(bib)
|
|
@@ -55,7 +56,8 @@ module Coradoc
|
|
|
55
56
|
id: bib.id,
|
|
56
57
|
title: bib.title.to_s,
|
|
57
58
|
level: nil,
|
|
58
|
-
entries: entries
|
|
59
|
+
entries: entries,
|
|
60
|
+
source_line: bib.source_line
|
|
59
61
|
)
|
|
60
62
|
end
|
|
61
63
|
|
|
@@ -63,7 +65,8 @@ module Coradoc
|
|
|
63
65
|
Coradoc::CoreModel::BibliographyEntry.new(
|
|
64
66
|
anchor_name: entry.anchor_name,
|
|
65
67
|
document_id: entry.document_id,
|
|
66
|
-
ref_text: entry.ref_text.to_s
|
|
68
|
+
ref_text: entry.ref_text.to_s,
|
|
69
|
+
source_line: entry.source_line
|
|
67
70
|
)
|
|
68
71
|
end
|
|
69
72
|
end
|
|
@@ -14,7 +14,8 @@ module Coradoc
|
|
|
14
14
|
Coradoc::CoreModel::Table.new(
|
|
15
15
|
id: table.id,
|
|
16
16
|
title: table.title&.to_s,
|
|
17
|
-
rows: rows
|
|
17
|
+
rows: rows,
|
|
18
|
+
source_line: table.source_line
|
|
18
19
|
)
|
|
19
20
|
end
|
|
20
21
|
|
|
@@ -24,7 +25,8 @@ module Coradoc
|
|
|
24
25
|
end
|
|
25
26
|
Coradoc::CoreModel::TableRow.new(
|
|
26
27
|
cells: cells,
|
|
27
|
-
header: row.header
|
|
28
|
+
header: row.header,
|
|
29
|
+
source_line: row.source_line
|
|
28
30
|
)
|
|
29
31
|
end
|
|
30
32
|
|
|
@@ -38,7 +40,8 @@ module Coradoc
|
|
|
38
40
|
colspan: cell.colspan,
|
|
39
41
|
rowspan: cell.rowspan,
|
|
40
42
|
style: cell.style_name,
|
|
41
|
-
children: children
|
|
43
|
+
children: children,
|
|
44
|
+
source_line: cell.source_line
|
|
42
45
|
)
|
|
43
46
|
end
|
|
44
47
|
end
|
|
@@ -38,18 +38,12 @@ module Coradoc
|
|
|
38
38
|
Coradoc::AsciiDoc::Model::Header.new(title: '')
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
# Pull FrontmatterBlock out first so strip_title_heading sees
|
|
42
|
-
# the body children in their natural order (frontmatter →
|
|
43
|
-
# title heading → body). The reverse-direction strip then
|
|
44
|
-
# matches on a level-0 HeaderElement wherever it sits among
|
|
45
|
-
# the remaining children.
|
|
46
41
|
without_frontmatter, frontmatter = extract_frontmatter(Array(element.children))
|
|
47
|
-
without_title = strip_title_heading(without_frontmatter, element.title)
|
|
48
42
|
|
|
49
43
|
Coradoc::AsciiDoc::Model::Document.new(
|
|
50
44
|
id: element.id,
|
|
51
45
|
header: header,
|
|
52
|
-
sections: flatten_children(
|
|
46
|
+
sections: flatten_children(without_frontmatter),
|
|
53
47
|
frontmatter: frontmatter
|
|
54
48
|
)
|
|
55
49
|
when CoreModel::SectionElement
|
|
@@ -68,27 +62,6 @@ module Coradoc
|
|
|
68
62
|
end
|
|
69
63
|
end
|
|
70
64
|
|
|
71
|
-
# The forward direction (DocumentTransformer#insert_title_heading_after_frontmatter)
|
|
72
|
-
# emits a level-0 HeaderElement after any FrontmatterBlock so
|
|
73
|
-
# consumers that walk the children see the title. On the reverse
|
|
74
|
-
# path, that HeaderElement would round-trip back as a separate
|
|
75
|
-
# body element and the title would be emitted twice (once via
|
|
76
|
-
# the document header, once via the heading child). Drop it
|
|
77
|
-
# before serialization when it carries the same text as the
|
|
78
|
-
# document title.
|
|
79
|
-
def strip_title_heading(children, document_title)
|
|
80
|
-
return children unless document_title && !document_title.strip.empty?
|
|
81
|
-
|
|
82
|
-
index = children.find_index do |child|
|
|
83
|
-
child.is_a?(CoreModel::HeaderElement) &&
|
|
84
|
-
child.level.to_i.zero? &&
|
|
85
|
-
child.title.to_s == document_title.to_s
|
|
86
|
-
end
|
|
87
|
-
return children unless index
|
|
88
|
-
|
|
89
|
-
children.reject.with_index { |_, i| i == index }
|
|
90
|
-
end
|
|
91
|
-
|
|
92
65
|
# Transforms each CoreModel child and flattens one level so a
|
|
93
66
|
# transform that returns multiple siblings (e.g. a source block
|
|
94
67
|
# followed by its re-expanded callout paragraphs) stays in
|
|
@@ -327,11 +300,17 @@ module Coradoc
|
|
|
327
300
|
end
|
|
328
301
|
|
|
329
302
|
def transform_image(image)
|
|
330
|
-
Coradoc::AsciiDoc::Model::Image::
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
303
|
+
target_class = image.inline ? Coradoc::AsciiDoc::Model::Image::InlineImage
|
|
304
|
+
: Coradoc::AsciiDoc::Model::Image::BlockImage
|
|
305
|
+
target_class.new(**image_attributes(image))
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def image_attributes(image)
|
|
309
|
+
{
|
|
310
|
+
src: image.src, alt: image.alt, title: image.title,
|
|
311
|
+
caption: image.caption, width: image.width, height: image.height,
|
|
312
|
+
link: image.link, role: image.role
|
|
313
|
+
}
|
|
335
314
|
end
|
|
336
315
|
|
|
337
316
|
def transform_bibliography(bib)
|
|
@@ -530,6 +509,10 @@ module Coradoc
|
|
|
530
509
|
content.map { |item| create_text_elements(item) }
|
|
531
510
|
when Coradoc::CoreModel::InlineElement
|
|
532
511
|
transform_inline(content)
|
|
512
|
+
when Coradoc::CoreModel::TextContent
|
|
513
|
+
Coradoc::AsciiDoc::Model::TextElement.new(content: content.text.to_s)
|
|
514
|
+
when Coradoc::CoreModel::Base
|
|
515
|
+
transform(content)
|
|
533
516
|
when Coradoc::AsciiDoc::Model::Base
|
|
534
517
|
content
|
|
535
518
|
when Lutaml::Model::Serializable
|
|
@@ -555,13 +538,6 @@ module Coradoc
|
|
|
555
538
|
attrs
|
|
556
539
|
end
|
|
557
540
|
|
|
558
|
-
def build_image_attributes(image)
|
|
559
|
-
attrs = {}
|
|
560
|
-
attrs['width'] = image.width if image.width
|
|
561
|
-
attrs['height'] = image.height if image.height
|
|
562
|
-
attrs
|
|
563
|
-
end
|
|
564
|
-
|
|
565
541
|
def default_marker(marker_type)
|
|
566
542
|
case marker_type
|
|
567
543
|
when 'ordered' then '.'
|
|
@@ -35,21 +35,39 @@ module Coradoc
|
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
# Folds soft source line breaks into a single text run: when two
|
|
39
|
+
# +Model::TextElement+s sit adjacent in the content array (the parser
|
|
40
|
+
# emits one per source line of a paragraph), a space is inserted
|
|
41
|
+
# between them so wrapped text renders as flowing prose rather than
|
|
42
|
+
# concatenated words.
|
|
43
|
+
#
|
|
44
|
+
# The previous item must ALSO be a TextElement — if a non-text
|
|
45
|
+
# inline (HardLineBreak, Passthrough, Image, etc.) sits between two
|
|
46
|
+
# TextElements, the source did not have a soft break there and no
|
|
47
|
+
# space should be synthesised. Without this guard, `foo +\nbar`
|
|
48
|
+
# would emit `["foo", hard_break, " ", "bar"]` (stray space) and
|
|
49
|
+
# `Before +pass:[RAW]+ after` would emit a double space around the
|
|
50
|
+
# passthrough.
|
|
38
51
|
def visit_array(items)
|
|
39
52
|
result = []
|
|
40
|
-
|
|
53
|
+
previous = nil
|
|
54
|
+
items.each do |item|
|
|
41
55
|
transformed = visit_content(item)
|
|
42
56
|
next if transformed.empty?
|
|
43
57
|
|
|
44
|
-
|
|
45
|
-
item.is_a?(Model::TextElement) &&
|
|
46
|
-
item.line_break != '+'
|
|
47
|
-
result << CoreModel::TextContent.new(text: ' ') if needs_space
|
|
58
|
+
result << CoreModel::TextContent.new(text: ' ') if soft_break_before?(previous, item)
|
|
48
59
|
result.concat(transformed)
|
|
60
|
+
previous = item
|
|
49
61
|
end
|
|
50
62
|
result
|
|
51
63
|
end
|
|
52
64
|
|
|
65
|
+
def soft_break_before?(previous, current)
|
|
66
|
+
previous.is_a?(Model::TextElement) &&
|
|
67
|
+
current.is_a?(Model::TextElement) &&
|
|
68
|
+
current.line_break != '+'
|
|
69
|
+
end
|
|
70
|
+
|
|
53
71
|
def visit_model(model)
|
|
54
72
|
@to_core_model.transform(model)
|
|
55
73
|
end
|
|
@@ -23,14 +23,38 @@ module Coradoc
|
|
|
23
23
|
transformer ? transformer.call(model) : model
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
# Returns the source-line view of an AsciiDoc content array as
|
|
27
|
+
# an Array<String>. Single source of truth for source-line
|
|
28
|
+
# extraction — every transformer that needs to populate
|
|
29
|
+
# CoreModel::Block#lines goes through here so the filtering
|
|
30
|
+
# rules (skip Model::LineBreak and Model::Break::PageBreak,
|
|
31
|
+
# which carry no renderable text) apply consistently.
|
|
32
|
+
def extract_source_lines(content)
|
|
33
|
+
Array(content).filter_map do |item|
|
|
34
|
+
next if item.is_a?(Coradoc::AsciiDoc::Model::LineBreak) ||
|
|
35
|
+
item.is_a?(Coradoc::AsciiDoc::Model::Break::PageBreak)
|
|
36
|
+
|
|
37
|
+
extract_text_content(item).to_s
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
26
41
|
def extract_block_lines(block)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
42
|
+
extract_source_lines(block.lines).join("\n")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Extracts the source_line of the first AsciiDoc::Model::Base in
|
|
46
|
+
# +content+. Single source of truth for source-line propagation
|
|
47
|
+
# from AsciiDoc::Model trees into CoreModel objects built from
|
|
48
|
+
# grouped content (e.g., paragraphs inside typed blocks).
|
|
49
|
+
# Returns nil when no model carries a source_line.
|
|
50
|
+
def extract_source_line(content)
|
|
51
|
+
Array(content).each do |item|
|
|
52
|
+
next unless item.is_a?(Coradoc::AsciiDoc::Model::Base)
|
|
53
|
+
|
|
54
|
+
line = item.source_line
|
|
55
|
+
return line if line
|
|
30
56
|
end
|
|
31
|
-
|
|
32
|
-
extract_text_content(line)
|
|
33
|
-
end.join("\n")
|
|
57
|
+
nil
|
|
34
58
|
end
|
|
35
59
|
|
|
36
60
|
def extract_title_text(title)
|
|
@@ -23,7 +23,8 @@ module Coradoc
|
|
|
23
23
|
title: title,
|
|
24
24
|
delimiter_len: delimiter.size,
|
|
25
25
|
lines: lines,
|
|
26
|
-
ordering: ordering
|
|
26
|
+
ordering: ordering,
|
|
27
|
+
source_line: SourceLineExtractor.extract(block)
|
|
27
28
|
}
|
|
28
29
|
# Markdown fences carry the language tag inline (```ruby);
|
|
29
30
|
# pass it through so the SourceCode classifier entry can set
|
|
@@ -34,7 +35,11 @@ module Coradoc
|
|
|
34
35
|
|
|
35
36
|
# Example
|
|
36
37
|
rule(example: sequence(:example)) do
|
|
37
|
-
Model::Block::Example.new(
|
|
38
|
+
Model::Block::Example.new(
|
|
39
|
+
title: '',
|
|
40
|
+
lines: example,
|
|
41
|
+
source_line: SourceLineExtractor.extract(example)
|
|
42
|
+
)
|
|
38
43
|
end
|
|
39
44
|
|
|
40
45
|
# Admonition. Canonicalise the type to uppercase so round-trips
|
|
@@ -45,7 +50,11 @@ module Coradoc
|
|
|
45
50
|
content: sequence(:content)
|
|
46
51
|
) do
|
|
47
52
|
canonical = Coradoc::AsciiDoc::Transform::ElementTransformers::AdmonitionStyles.canonicalize(admonition_type.to_s)
|
|
48
|
-
Model::Admonition.new(
|
|
53
|
+
Model::Admonition.new(
|
|
54
|
+
content: content,
|
|
55
|
+
type: canonical,
|
|
56
|
+
source_line: SourceLineExtractor.extract(admonition_type)
|
|
57
|
+
)
|
|
49
58
|
end
|
|
50
59
|
|
|
51
60
|
# Block image
|
|
@@ -54,12 +63,17 @@ module Coradoc
|
|
|
54
63
|
title = block_image[:title]
|
|
55
64
|
path = block_image[:path]
|
|
56
65
|
attrs = AttributeListNormalizer.coerce(block_image[:attribute_list_macro])
|
|
66
|
+
promoted, residual = Model::Image::AttributeExtractor.call(
|
|
67
|
+
attrs, Model::Image::BlockImage
|
|
68
|
+
)
|
|
57
69
|
Model::Image::BlockImage.new(
|
|
58
70
|
title: title,
|
|
59
71
|
id: id,
|
|
60
72
|
src: path,
|
|
61
|
-
attributes:
|
|
62
|
-
line_break: "\n"
|
|
73
|
+
attributes: residual,
|
|
74
|
+
line_break: "\n",
|
|
75
|
+
source_line: SourceLineExtractor.extract(block_image),
|
|
76
|
+
**promoted
|
|
63
77
|
)
|
|
64
78
|
end
|
|
65
79
|
end
|
|
@@ -21,7 +21,10 @@ module Coradoc
|
|
|
21
21
|
id = id.to_s unless id.nil?
|
|
22
22
|
id = nil if id && id.empty?
|
|
23
23
|
|
|
24
|
-
Model::Header.new(
|
|
24
|
+
Model::Header.new(
|
|
25
|
+
id:, title:, author:, revision:,
|
|
26
|
+
source_line: SourceLineExtractor.extract(header)
|
|
27
|
+
)
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
rule(header: simple(:header)) do
|
|
@@ -34,7 +37,10 @@ module Coradoc
|
|
|
34
37
|
last_name: simple(:last_name),
|
|
35
38
|
email: simple(:email)
|
|
36
39
|
) do
|
|
37
|
-
Model::Author.new(
|
|
40
|
+
Model::Author.new(
|
|
41
|
+
first_name:, last_name:, email:, middle_name: nil,
|
|
42
|
+
source_line: SourceLineExtractor.extract(first_name)
|
|
43
|
+
)
|
|
38
44
|
end
|
|
39
45
|
|
|
40
46
|
# Revision
|
|
@@ -43,7 +49,10 @@ module Coradoc
|
|
|
43
49
|
date: simple(:date),
|
|
44
50
|
remark: simple(:remark)
|
|
45
51
|
) do
|
|
46
|
-
Model::Revision.new(
|
|
52
|
+
Model::Revision.new(
|
|
53
|
+
number:, date:, remark:,
|
|
54
|
+
source_line: SourceLineExtractor.extract(number)
|
|
55
|
+
)
|
|
47
56
|
end
|
|
48
57
|
end
|
|
49
58
|
end
|
|
@@ -22,7 +22,8 @@ module Coradoc
|
|
|
22
22
|
rule(link: subtree(:link)) do
|
|
23
23
|
Model::Inline::Link.new(
|
|
24
24
|
path: link[:path].to_s,
|
|
25
|
-
name: link[:text]&.to_s
|
|
25
|
+
name: link[:text]&.to_s,
|
|
26
|
+
source_line: SourceLineExtractor.extract(link)
|
|
26
27
|
)
|
|
27
28
|
end
|
|
28
29
|
|
|
@@ -31,15 +32,23 @@ module Coradoc
|
|
|
31
32
|
href = xref[:href].to_s
|
|
32
33
|
text = xref[:text]
|
|
33
34
|
args = text ? [text.to_s] : []
|
|
34
|
-
Model::Inline::CrossReference.new(
|
|
35
|
+
Model::Inline::CrossReference.new(
|
|
36
|
+
href:, args:,
|
|
37
|
+
source_line: SourceLineExtractor.extract(xref)
|
|
38
|
+
)
|
|
35
39
|
end
|
|
36
40
|
|
|
37
41
|
# Inline image
|
|
38
42
|
rule(inline_image: subtree(:inline_image)) do
|
|
39
43
|
attrs = AttributeListNormalizer.coerce(inline_image[:attribute_list])
|
|
44
|
+
promoted, residual = Model::Image::AttributeExtractor.call(
|
|
45
|
+
attrs, Model::Image::InlineImage
|
|
46
|
+
)
|
|
40
47
|
Model::Image::InlineImage.new(
|
|
41
48
|
src: inline_image[:path],
|
|
42
|
-
attributes:
|
|
49
|
+
attributes: residual,
|
|
50
|
+
source_line: SourceLineExtractor.extract(inline_image),
|
|
51
|
+
**promoted
|
|
43
52
|
)
|
|
44
53
|
end
|
|
45
54
|
|
|
@@ -50,13 +59,17 @@ module Coradoc
|
|
|
50
59
|
rule(inline_passthrough: subtree(:passthrough)) do
|
|
51
60
|
Model::Inline::Passthrough.new(
|
|
52
61
|
content: passthrough[:raw].to_s,
|
|
53
|
-
form: 'triple'
|
|
62
|
+
form: 'triple',
|
|
63
|
+
source_line: SourceLineExtractor.extract(passthrough)
|
|
54
64
|
)
|
|
55
65
|
end
|
|
56
66
|
|
|
57
67
|
# Attribute reference
|
|
58
68
|
rule(attribute_reference: simple(:name)) do
|
|
59
|
-
Model::Inline::AttributeReference.new(
|
|
69
|
+
Model::Inline::AttributeReference.new(
|
|
70
|
+
name:,
|
|
71
|
+
source_line: SourceLineExtractor.extract(name)
|
|
72
|
+
)
|
|
60
73
|
end
|
|
61
74
|
|
|
62
75
|
# Hard line break (` +\n` or `\\n`). Emitted as a dedicated
|
|
@@ -64,8 +77,10 @@ module Coradoc
|
|
|
64
77
|
# Model::LineBreak, which only represents paragraph-separator
|
|
65
78
|
# blank lines. Hard breaks carry semantic meaning: HTML/Markdown
|
|
66
79
|
# renderers map them to <br>.
|
|
67
|
-
rule(hard_line_break: simple(:
|
|
68
|
-
Model::Inline::HardLineBreak.new
|
|
80
|
+
rule(hard_line_break: simple(:hard_line_break)) do
|
|
81
|
+
Model::Inline::HardLineBreak.new(
|
|
82
|
+
source_line: SourceLineExtractor.extract(hard_line_break)
|
|
83
|
+
)
|
|
69
84
|
end
|
|
70
85
|
|
|
71
86
|
# Term
|
|
@@ -73,30 +88,45 @@ module Coradoc
|
|
|
73
88
|
term_type: simple(:term_type),
|
|
74
89
|
term: simple(:term)
|
|
75
90
|
) do
|
|
76
|
-
Coradoc::AsciiDoc::Model::Term.new(
|
|
91
|
+
Coradoc::AsciiDoc::Model::Term.new(
|
|
92
|
+
term:, type: term_type, lang: :en,
|
|
93
|
+
source_line: SourceLineExtractor.extract(term_type)
|
|
94
|
+
)
|
|
77
95
|
end
|
|
78
96
|
|
|
79
97
|
# Footnote
|
|
80
98
|
rule(footnote: simple(:footnote)) do
|
|
81
99
|
text_str = footnote.to_s
|
|
82
|
-
Coradoc::AsciiDoc::Model::Inline::Footnote.new(
|
|
100
|
+
Coradoc::AsciiDoc::Model::Inline::Footnote.new(
|
|
101
|
+
text: text_str,
|
|
102
|
+
source_line: SourceLineExtractor.extract(footnote)
|
|
103
|
+
)
|
|
83
104
|
end
|
|
84
105
|
|
|
85
106
|
rule(footnote: simple(:footnote), id: simple(:id)) do
|
|
86
107
|
text_str = footnote.to_s
|
|
87
|
-
Coradoc::AsciiDoc::Model::Inline::Footnote.new(
|
|
108
|
+
Coradoc::AsciiDoc::Model::Inline::Footnote.new(
|
|
109
|
+
text: text_str, id: id.to_s,
|
|
110
|
+
source_line: SourceLineExtractor.extract(footnote)
|
|
111
|
+
)
|
|
88
112
|
end
|
|
89
113
|
|
|
90
114
|
# Footnote with empty content (reference to named footnote)
|
|
91
115
|
rule(footnote: sequence(:footnote), id: simple(:id)) do
|
|
92
116
|
text_str = footnote.map(&:to_s).join
|
|
93
|
-
Coradoc::AsciiDoc::Model::Inline::Footnote.new(
|
|
117
|
+
Coradoc::AsciiDoc::Model::Inline::Footnote.new(
|
|
118
|
+
text: text_str, id: id.to_s,
|
|
119
|
+
source_line: SourceLineExtractor.extract(footnote)
|
|
120
|
+
)
|
|
94
121
|
end
|
|
95
122
|
|
|
96
123
|
# Footnote with empty content and no id
|
|
97
124
|
rule(footnote: sequence(:footnote)) do
|
|
98
125
|
text_str = footnote.map(&:to_s).join
|
|
99
|
-
Coradoc::AsciiDoc::Model::Inline::Footnote.new(
|
|
126
|
+
Coradoc::AsciiDoc::Model::Inline::Footnote.new(
|
|
127
|
+
text: text_str,
|
|
128
|
+
source_line: SourceLineExtractor.extract(footnote)
|
|
129
|
+
)
|
|
100
130
|
end
|
|
101
131
|
|
|
102
132
|
# Inline formatting rules generated from a single registry.
|
|
@@ -110,11 +140,17 @@ module Coradoc
|
|
|
110
140
|
|
|
111
141
|
rule(constrained_key => subtree(:subtree)) do
|
|
112
142
|
content = Transformer.extract_inline_content(subtree)
|
|
113
|
-
klass.new(
|
|
143
|
+
klass.new(
|
|
144
|
+
content: content, unconstrained: false,
|
|
145
|
+
source_line: SourceLineExtractor.extract(subtree)
|
|
146
|
+
)
|
|
114
147
|
end
|
|
115
148
|
rule(unconstrained_key => subtree(:subtree)) do
|
|
116
149
|
content = Transformer.extract_inline_content(subtree)
|
|
117
|
-
klass.new(
|
|
150
|
+
klass.new(
|
|
151
|
+
content: content, unconstrained: true,
|
|
152
|
+
source_line: SourceLineExtractor.extract(subtree)
|
|
153
|
+
)
|
|
118
154
|
end
|
|
119
155
|
end
|
|
120
156
|
|
|
@@ -123,7 +159,8 @@ module Coradoc
|
|
|
123
159
|
Model::Inline::Span.new(
|
|
124
160
|
text: span_constrained[:text],
|
|
125
161
|
unconstrained: false,
|
|
126
|
-
attributes: span_constrained[:attribute_list]
|
|
162
|
+
attributes: span_constrained[:attribute_list],
|
|
163
|
+
source_line: SourceLineExtractor.extract(span_constrained)
|
|
127
164
|
)
|
|
128
165
|
end
|
|
129
166
|
|
|
@@ -132,31 +169,42 @@ module Coradoc
|
|
|
132
169
|
Model::Inline::Span.new(
|
|
133
170
|
text: span_unconstrained[:text],
|
|
134
171
|
unconstrained: true,
|
|
135
|
-
attributes: span_unconstrained[:attribute_list]
|
|
172
|
+
attributes: span_unconstrained[:attribute_list],
|
|
173
|
+
source_line: SourceLineExtractor.extract(span_unconstrained)
|
|
136
174
|
)
|
|
137
175
|
end
|
|
138
176
|
|
|
139
177
|
# Superscript
|
|
140
178
|
rule(superscript: subtree(:superscript)) do
|
|
141
179
|
content = Transformer.extract_simple_inline_content(superscript)
|
|
142
|
-
Model::Inline::Superscript.new(
|
|
180
|
+
Model::Inline::Superscript.new(
|
|
181
|
+
content:,
|
|
182
|
+
source_line: SourceLineExtractor.extract(superscript)
|
|
183
|
+
)
|
|
143
184
|
end
|
|
144
185
|
|
|
145
186
|
# Subscript
|
|
146
187
|
rule(subscript: subtree(:subscript)) do
|
|
147
188
|
content = Transformer.extract_simple_inline_content(subscript)
|
|
148
|
-
Model::Inline::Subscript.new(
|
|
189
|
+
Model::Inline::Subscript.new(
|
|
190
|
+
content:,
|
|
191
|
+
source_line: SourceLineExtractor.extract(subscript)
|
|
192
|
+
)
|
|
149
193
|
end
|
|
150
194
|
|
|
151
195
|
# Highlight (simple)
|
|
152
196
|
rule(highlight: simple(:text)) do
|
|
153
|
-
Model::Highlight.new(
|
|
197
|
+
Model::Highlight.new(
|
|
198
|
+
content: text,
|
|
199
|
+
source_line: SourceLineExtractor.extract(text)
|
|
200
|
+
)
|
|
154
201
|
end
|
|
155
202
|
# Stem
|
|
156
203
|
rule(stem: subtree(:stem)) do
|
|
157
204
|
Coradoc::AsciiDoc::Model::Inline::Stem.new(
|
|
158
205
|
type: stem[:stem_type],
|
|
159
|
-
content: stem[:content]
|
|
206
|
+
content: stem[:content],
|
|
207
|
+
source_line: SourceLineExtractor.extract(stem)
|
|
160
208
|
)
|
|
161
209
|
end
|
|
162
210
|
end
|
|
@@ -74,7 +74,8 @@ module Coradoc
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
Model::List::Item.new(
|
|
77
|
-
content: content, id:, marker:, attached:, nested:, line_break
|
|
77
|
+
content: content, id:, marker:, attached:, nested:, line_break:,
|
|
78
|
+
source_line: SourceLineExtractor.extract(list_item)
|
|
78
79
|
)
|
|
79
80
|
end
|
|
80
81
|
|
|
@@ -85,26 +86,40 @@ module Coradoc
|
|
|
85
86
|
|
|
86
87
|
# Unordered list
|
|
87
88
|
rule(unordered: sequence(:list_items)) do
|
|
88
|
-
Model::List::Unordered.new(
|
|
89
|
+
Model::List::Unordered.new(
|
|
90
|
+
items: list_items,
|
|
91
|
+
source_line: SourceLineExtractor.extract(list_items)
|
|
92
|
+
)
|
|
89
93
|
end
|
|
90
94
|
|
|
91
95
|
rule(
|
|
92
96
|
attribute_list: simple(:attribute_list),
|
|
93
97
|
unordered: sequence(:list_items)
|
|
94
98
|
) do
|
|
95
|
-
Model::List::Unordered.new(
|
|
99
|
+
Model::List::Unordered.new(
|
|
100
|
+
items: list_items,
|
|
101
|
+
attrs: attribute_list,
|
|
102
|
+
source_line: SourceLineExtractor.extract(attribute_list)
|
|
103
|
+
)
|
|
96
104
|
end
|
|
97
105
|
|
|
98
106
|
# Ordered list
|
|
99
107
|
rule(ordered: sequence(:list_items)) do
|
|
100
|
-
Model::List::Ordered.new(
|
|
108
|
+
Model::List::Ordered.new(
|
|
109
|
+
items: list_items,
|
|
110
|
+
source_line: SourceLineExtractor.extract(list_items)
|
|
111
|
+
)
|
|
101
112
|
end
|
|
102
113
|
|
|
103
114
|
rule(
|
|
104
115
|
attribute_list: simple(:attribute_list),
|
|
105
116
|
ordered: sequence(:list_items)
|
|
106
117
|
) do
|
|
107
|
-
Model::List::Ordered.new(
|
|
118
|
+
Model::List::Ordered.new(
|
|
119
|
+
items: list_items,
|
|
120
|
+
attrs: attribute_list,
|
|
121
|
+
source_line: SourceLineExtractor.extract(attribute_list)
|
|
122
|
+
)
|
|
108
123
|
end
|
|
109
124
|
|
|
110
125
|
# Definition list term (with optional anchor)
|