coradoc-adoc 2.0.35 → 2.0.36
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/grammar/coradoc-adoc.artifact.json +1 -0
- data/grammar/coradoc-adoc.parg +396 -0
- data/lib/coradoc/asciidoc/formatter.rb +75 -0
- data/lib/coradoc/asciidoc/lint/document_title.rb +26 -0
- data/lib/coradoc/asciidoc/lint/duplicate_ids.rb +36 -0
- data/lib/coradoc/asciidoc/lint/empty_section.rb +45 -0
- data/lib/coradoc/asciidoc/lint/heading_levels.rb +44 -0
- data/lib/coradoc/asciidoc/lint.rb +27 -0
- data/lib/coradoc/asciidoc/model/text_element.rb +18 -5
- data/lib/coradoc/asciidoc/parser/base.rb +28 -11
- data/lib/coradoc/asciidoc/parser/citation.rb +10 -0
- data/lib/coradoc/asciidoc/parser/inline.rb +8 -4
- data/lib/coradoc/asciidoc/parser/list.rb +19 -2
- data/lib/coradoc/asciidoc/parser/paragraph.rb +1 -1
- data/lib/coradoc/asciidoc/parser/positioned_string.rb +40 -0
- data/lib/coradoc/asciidoc/parser/rule_dispatcher.rb +3 -2
- data/lib/coradoc/asciidoc/parser/tree_materializer.rb +28 -0
- data/lib/coradoc/asciidoc/parser.rb +2 -0
- data/lib/coradoc/asciidoc/serializer/serializers/block/source_code.rb +3 -1
- data/lib/coradoc/asciidoc/serializer/serializers/list/item.rb +4 -0
- data/lib/coradoc/asciidoc/serializer/serializers/table.rb +8 -2
- data/lib/coradoc/asciidoc/serializer/serializers/text_element.rb +3 -1
- data/lib/coradoc/asciidoc/transform/from_core_model/list_building.rb +86 -0
- data/lib/coradoc/asciidoc/transform/from_core_model.rb +100 -29
- data/lib/coradoc/asciidoc/transform/frontmatter_attribute_map.rb +3 -2
- data/lib/coradoc/asciidoc/transform/text_extract_visitor.rb +5 -2
- data/lib/coradoc/asciidoc/transform/to_core_model.rb +12 -2
- data/lib/coradoc/asciidoc/transform.rb +1 -0
- data/lib/coradoc/asciidoc/transformer/source_line_extractor.rb +1 -1
- data/lib/coradoc/asciidoc/transformer/table_cell_builder.rb +18 -7
- data/lib/coradoc/asciidoc/version.rb +1 -1
- data/lib/coradoc/asciidoc.rb +12 -0
- data/lib/coradoc/util/asciidoc.rb +56 -0
- metadata +16 -5
|
@@ -109,15 +109,18 @@ module Coradoc
|
|
|
109
109
|
|
|
110
110
|
# Collections
|
|
111
111
|
def visit_array(models)
|
|
112
|
+
# Fragments of one source line concatenate (an escape splits
|
|
113
|
+
# `foo\_bar` into three pieces); a soft line break joins
|
|
114
|
+
# with a space (soft-wrapped paragraph lines).
|
|
112
115
|
result = []
|
|
113
116
|
models.each_with_index do |item, idx|
|
|
114
117
|
text = visit(item)
|
|
115
118
|
next if text.empty?
|
|
116
119
|
|
|
117
120
|
result << text
|
|
118
|
-
next
|
|
121
|
+
next if idx == models.length - 1
|
|
119
122
|
|
|
120
|
-
result << ' ' if item.is_a?(Model::TextElement) && item.line_break
|
|
123
|
+
result << ' ' if item.is_a?(Model::TextElement) && item.line_break == "\n"
|
|
121
124
|
end
|
|
122
125
|
result.join
|
|
123
126
|
end
|
|
@@ -108,12 +108,22 @@ module Coradoc
|
|
|
108
108
|
DelimiterMapping::CHAR_TO_SEMANTIC[char] || :open
|
|
109
109
|
end
|
|
110
110
|
|
|
111
|
+
# Reused parser/transformer for inline re-parsing: Parsanol's
|
|
112
|
+
# VM program cache is keyed by atom identity, so a fresh parser
|
|
113
|
+
# per call recompiled the grammar every time (see also
|
|
114
|
+
# Transformer::TableCellBuilder).
|
|
115
|
+
def inline_reparse
|
|
116
|
+
@inline_reparse ||= [
|
|
117
|
+
Coradoc::AsciiDoc::Parser::Base.new,
|
|
118
|
+
Coradoc::AsciiDoc::Transformer.new
|
|
119
|
+
]
|
|
120
|
+
end
|
|
121
|
+
|
|
111
122
|
def parse_inline_text(raw_text)
|
|
112
123
|
return [] if raw_text.nil? || raw_text.to_s.strip.empty?
|
|
113
124
|
|
|
114
125
|
text = raw_text.to_s
|
|
115
|
-
parser =
|
|
116
|
-
transformer = Coradoc::AsciiDoc::Transformer.new
|
|
126
|
+
parser, transformer = inline_reparse
|
|
117
127
|
|
|
118
128
|
parsed = parser.text_any.parse(text)
|
|
119
129
|
result = transformer.apply({ text: parsed })
|
|
@@ -8,6 +8,7 @@ module Coradoc
|
|
|
8
8
|
autoload :ToCoreModel, "#{__dir__}/transform/to_core_model"
|
|
9
9
|
autoload :ToCoreModelRegistrations, "#{__dir__}/transform/to_core_model_registrations"
|
|
10
10
|
autoload :FromCoreModel, "#{__dir__}/transform/from_core_model"
|
|
11
|
+
autoload :ListBuilding, "#{__dir__}/transform/from_core_model/list_building"
|
|
11
12
|
autoload :FromCoreModelRegistrations, "#{__dir__}/transform/from_core_model_registrations"
|
|
12
13
|
autoload :TextExtractVisitor, "#{__dir__}/transform/text_extract_visitor"
|
|
13
14
|
autoload :InlineTransformVisitor, "#{__dir__}/transform/inline_transform_visitor"
|
|
@@ -33,7 +33,7 @@ module Coradoc
|
|
|
33
33
|
|
|
34
34
|
def extract(node)
|
|
35
35
|
case node
|
|
36
|
-
when Parsanol::Slice then line_of(node)
|
|
36
|
+
when Parsanol::Slice, Coradoc::AsciiDoc::Parser::PositionedString then line_of(node)
|
|
37
37
|
when Coradoc::AsciiDoc::Model::Base then node.source_line
|
|
38
38
|
when Hash then extract_from_hash(node)
|
|
39
39
|
when Array then extract_from_array(node)
|
|
@@ -13,6 +13,16 @@ module Coradoc
|
|
|
13
13
|
module TableCellBuilder
|
|
14
14
|
module_function
|
|
15
15
|
|
|
16
|
+
# Reused parser for cell-content re-parsing. Atoms are memoized
|
|
17
|
+
# per parser instance and Parsanol's VM program cache is keyed by
|
|
18
|
+
# atom identity — a fresh parser per cell recompiled the whole
|
|
19
|
+
# grammar for every cell (tables transformed ~50× slower than
|
|
20
|
+
# they parsed). Sequential reuse only; parse state lives in the
|
|
21
|
+
# per-call context, not the parser.
|
|
22
|
+
def inline_parser
|
|
23
|
+
@inline_parser ||= Coradoc::AsciiDoc::Parser::Base.new
|
|
24
|
+
end
|
|
25
|
+
|
|
16
26
|
# @param format [Hash, String, Object, nil] Cell format from parser
|
|
17
27
|
# @param content [Object] Cell content
|
|
18
28
|
# @return [Model::TableCell]
|
|
@@ -59,14 +69,15 @@ module Coradoc
|
|
|
59
69
|
# @param style [String, nil] 'a' (AsciiDoc), 'l' (literal), or nil
|
|
60
70
|
# @return [Array<Model::TextElement>]
|
|
61
71
|
def parse_inline_content(text, style = nil)
|
|
62
|
-
|
|
72
|
+
text = text.to_s.strip unless style == 'l'
|
|
73
|
+
return [Model::TextElement.new(content: '')] if text.empty?
|
|
63
74
|
|
|
64
75
|
return parse_block_content(text) if style == 'a'
|
|
65
76
|
return [Model::TextElement.new(content: text.to_s)] if style == 'l'
|
|
66
77
|
|
|
67
|
-
parser =
|
|
78
|
+
parser = inline_parser
|
|
68
79
|
begin
|
|
69
|
-
ast = parser.text_any.parse(text.to_s)
|
|
80
|
+
ast = Parser::TreeMaterializer.convert(parser.text_any.parse(text.to_s))
|
|
70
81
|
transformed = Transformer.new.apply(ast)
|
|
71
82
|
content_array = transformed.is_a?(Array) ? transformed : [transformed]
|
|
72
83
|
[Model::TextElement.new(content: content_array)]
|
|
@@ -81,7 +92,7 @@ module Coradoc
|
|
|
81
92
|
def parse_block_content(text)
|
|
82
93
|
return [Model::TextElement.new(content: '')] if text.nil? || text.to_s.strip.empty?
|
|
83
94
|
|
|
84
|
-
parser =
|
|
95
|
+
parser = inline_parser
|
|
85
96
|
text_str = text.to_s
|
|
86
97
|
|
|
87
98
|
if /^(\*+|-+|\d+\.)/m.match?(text_str)
|
|
@@ -89,14 +100,14 @@ module Coradoc
|
|
|
89
100
|
if list_match
|
|
90
101
|
list_text = list_match[1] + list_match[2]
|
|
91
102
|
begin
|
|
92
|
-
ast = parser.list.parse(list_text)
|
|
103
|
+
ast = Parser::TreeMaterializer.convert(parser.list.parse(list_text))
|
|
93
104
|
transformed = Transformer.new.apply(ast)
|
|
94
105
|
|
|
95
106
|
before_list = text_str[0, list_match.begin(1) - 1].strip
|
|
96
107
|
before_elements = []
|
|
97
108
|
unless before_list.empty?
|
|
98
109
|
begin
|
|
99
|
-
before_ast = parser.text_any.parse(before_list)
|
|
110
|
+
before_ast = Parser::TreeMaterializer.convert(parser.text_any.parse(before_list))
|
|
100
111
|
before_transformed = Transformer.new.apply(before_ast)
|
|
101
112
|
before_array = before_transformed.is_a?(Array) ? before_transformed : [before_transformed]
|
|
102
113
|
before_elements = [Model::TextElement.new(content: before_array)]
|
|
@@ -113,7 +124,7 @@ module Coradoc
|
|
|
113
124
|
end
|
|
114
125
|
|
|
115
126
|
begin
|
|
116
|
-
ast = parser.text_any.parse(text_str)
|
|
127
|
+
ast = Parser::TreeMaterializer.convert(parser.text_any.parse(text_str))
|
|
117
128
|
transformed = Transformer.new.apply(ast)
|
|
118
129
|
content_array = transformed.is_a?(Array) ? transformed : [transformed]
|
|
119
130
|
[Model::TextElement.new(content: content_array)]
|
data/lib/coradoc/asciidoc.rb
CHANGED
|
@@ -32,6 +32,9 @@ module Coradoc
|
|
|
32
32
|
autoload :Model, "#{__dir__}/asciidoc/model"
|
|
33
33
|
autoload :Parser, "#{__dir__}/asciidoc/parser"
|
|
34
34
|
autoload :Transformer, "#{__dir__}/asciidoc/transformer"
|
|
35
|
+
# Registration side effect: loading registers rules into Coradoc::Lint.registry.
|
|
36
|
+
autoload :Lint, "#{__dir__}/asciidoc/lint"
|
|
37
|
+
autoload :Formatter, "#{__dir__}/asciidoc/formatter"
|
|
35
38
|
autoload :Serializer, "#{__dir__}/asciidoc/serializer"
|
|
36
39
|
autoload :Transform, "#{__dir__}/asciidoc/transform"
|
|
37
40
|
autoload :Builder, "#{__dir__}/asciidoc/builder"
|
|
@@ -79,6 +82,15 @@ module Coradoc
|
|
|
79
82
|
Transform::ToCoreModel.transform(document)
|
|
80
83
|
end
|
|
81
84
|
|
|
85
|
+
# Canonical-format AsciiDoc text (#110): parse to the model
|
|
86
|
+
# tree, serialize, and normalize inter-block whitespace.
|
|
87
|
+
#
|
|
88
|
+
# @param text [String] AsciiDoc content
|
|
89
|
+
# @return [String] canonically formatted AsciiDoc
|
|
90
|
+
def format(text)
|
|
91
|
+
Formatter.call(text)
|
|
92
|
+
end
|
|
93
|
+
|
|
82
94
|
# Serialize a document model to AsciiDoc string
|
|
83
95
|
#
|
|
84
96
|
# @param document [Coradoc::AsciiDoc::Model::Document, Coradoc::CoreModel::Base]
|
|
@@ -50,6 +50,62 @@ module Coradoc
|
|
|
50
50
|
result
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
# Escape delimiter characters in plain-text content so the text
|
|
54
|
+
# survives a reparse (#92): `__x__`, `**x**`, `x~2~` and `` `x` ``
|
|
55
|
+
# would otherwise re-enter as formatting. Runs of two or more
|
|
56
|
+
# delimiters (`__`, `**`, `~~`) are dangerous anywhere; a single
|
|
57
|
+
# `*`, `_` or `~` only forms a constrained pair at a
|
|
58
|
+
# boundary/word transition; `^` and `` ` `` attach to words.
|
|
59
|
+
def self.escape_text_delimiters(text)
|
|
60
|
+
return '' if text.nil?
|
|
61
|
+
|
|
62
|
+
text.to_s.gsub(/(?<!\\)[`*_~^]+/) do |run|
|
|
63
|
+
match = Regexp.last_match
|
|
64
|
+
dangerous =
|
|
65
|
+
case run[0]
|
|
66
|
+
when '`'
|
|
67
|
+
true
|
|
68
|
+
when '^'
|
|
69
|
+
word_transition?(text, match)
|
|
70
|
+
else
|
|
71
|
+
run.length >= 2 || word_transition?(text, match)
|
|
72
|
+
end
|
|
73
|
+
dangerous ? run.chars.map { |c| "\\#{c}" }.join : run
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
WHITESPACE = /\s/
|
|
78
|
+
WORD_CHAR = /[[:word:]]/
|
|
79
|
+
PUNCT_CHAR = /[[:punct:]]/
|
|
80
|
+
private_constant :WHITESPACE, :WORD_CHAR, :PUNCT_CHAR
|
|
81
|
+
|
|
82
|
+
# A delimiter run at [start, stop) is dangerous when it can open
|
|
83
|
+
# a pair (boundary on its left, word char on its right) or close
|
|
84
|
+
# one (word char on its left, boundary-or-punctuation on its
|
|
85
|
+
# right — AsciiDoc lets a closing delimiter precede punctuation).
|
|
86
|
+
def self.word_transition?(text, match)
|
|
87
|
+
start = match.begin(0)
|
|
88
|
+
stop = match.end(0)
|
|
89
|
+
before = start.zero? ? nil : text[start - 1]
|
|
90
|
+
after = stop >= text.length ? nil : text[stop]
|
|
91
|
+
|
|
92
|
+
opens = boundary?(before) && word?(after)
|
|
93
|
+
closes = word?(before) && (boundary?(after) || punctuation?(after))
|
|
94
|
+
opens || closes
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def self.boundary?(char)
|
|
98
|
+
char.nil? || char.match?(WHITESPACE)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def self.word?(char)
|
|
102
|
+
!char.nil? && char.match?(WORD_CHAR)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def self.punctuation?(char)
|
|
106
|
+
!char.nil? && char.match?(PUNCT_CHAR)
|
|
107
|
+
end
|
|
108
|
+
|
|
53
109
|
# Unescape AsciiDoc characters in content
|
|
54
110
|
#
|
|
55
111
|
# @param content [String] The content to unescape
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: coradoc-adoc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.
|
|
4
|
+
version: 2.0.36
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -41,16 +41,16 @@ dependencies:
|
|
|
41
41
|
name: parsanol
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
|
-
- - "
|
|
44
|
+
- - "~>"
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version:
|
|
46
|
+
version: 1.3.123
|
|
47
47
|
type: :runtime
|
|
48
48
|
prerelease: false
|
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
50
|
requirements:
|
|
51
|
-
- - "
|
|
51
|
+
- - "~>"
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
|
-
version:
|
|
53
|
+
version: 1.3.123
|
|
54
54
|
- !ruby/object:Gem::Dependency
|
|
55
55
|
name: rake
|
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -104,6 +104,8 @@ extra_rdoc_files: []
|
|
|
104
104
|
files:
|
|
105
105
|
- ".rspec"
|
|
106
106
|
- Rakefile
|
|
107
|
+
- grammar/coradoc-adoc.artifact.json
|
|
108
|
+
- grammar/coradoc-adoc.parg
|
|
107
109
|
- lib/coradoc/asciidoc.rb
|
|
108
110
|
- lib/coradoc/asciidoc/builder.rb
|
|
109
111
|
- lib/coradoc/asciidoc/builder/block_builder.rb
|
|
@@ -112,6 +114,12 @@ files:
|
|
|
112
114
|
- lib/coradoc/asciidoc/builder/list_builder.rb
|
|
113
115
|
- lib/coradoc/asciidoc/builder/text_builder.rb
|
|
114
116
|
- lib/coradoc/asciidoc/delimiter_mapping.rb
|
|
117
|
+
- lib/coradoc/asciidoc/formatter.rb
|
|
118
|
+
- lib/coradoc/asciidoc/lint.rb
|
|
119
|
+
- lib/coradoc/asciidoc/lint/document_title.rb
|
|
120
|
+
- lib/coradoc/asciidoc/lint/duplicate_ids.rb
|
|
121
|
+
- lib/coradoc/asciidoc/lint/empty_section.rb
|
|
122
|
+
- lib/coradoc/asciidoc/lint/heading_levels.rb
|
|
115
123
|
- lib/coradoc/asciidoc/model.rb
|
|
116
124
|
- lib/coradoc/asciidoc/model/admonition.rb
|
|
117
125
|
- lib/coradoc/asciidoc/model/anchorable.rb
|
|
@@ -229,12 +237,14 @@ files:
|
|
|
229
237
|
- lib/coradoc/asciidoc/parser/list.rb
|
|
230
238
|
- lib/coradoc/asciidoc/parser/metadata_detector.rb
|
|
231
239
|
- lib/coradoc/asciidoc/parser/paragraph.rb
|
|
240
|
+
- lib/coradoc/asciidoc/parser/positioned_string.rb
|
|
232
241
|
- lib/coradoc/asciidoc/parser/rule_dispatcher.rb
|
|
233
242
|
- lib/coradoc/asciidoc/parser/section.rb
|
|
234
243
|
- lib/coradoc/asciidoc/parser/stem.rb
|
|
235
244
|
- lib/coradoc/asciidoc/parser/table.rb
|
|
236
245
|
- lib/coradoc/asciidoc/parser/term.rb
|
|
237
246
|
- lib/coradoc/asciidoc/parser/text.rb
|
|
247
|
+
- lib/coradoc/asciidoc/parser/tree_materializer.rb
|
|
238
248
|
- lib/coradoc/asciidoc/reference_materializers.rb
|
|
239
249
|
- lib/coradoc/asciidoc/reference_materializers/navigation.rb
|
|
240
250
|
- lib/coradoc/asciidoc/serializer.rb
|
|
@@ -330,6 +340,7 @@ files:
|
|
|
330
340
|
- lib/coradoc/asciidoc/transform/element_transformers/other_transformer.rb
|
|
331
341
|
- lib/coradoc/asciidoc/transform/element_transformers/table_transformer.rb
|
|
332
342
|
- lib/coradoc/asciidoc/transform/from_core_model.rb
|
|
343
|
+
- lib/coradoc/asciidoc/transform/from_core_model/list_building.rb
|
|
333
344
|
- lib/coradoc/asciidoc/transform/from_core_model_registrations.rb
|
|
334
345
|
- lib/coradoc/asciidoc/transform/frontmatter_attribute_map.rb
|
|
335
346
|
- lib/coradoc/asciidoc/transform/inline_transform_visitor.rb
|