coradoc-adoc 2.0.18 → 2.0.19

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d8b381debf5d0742992318f775804846b9a2560e59dcff0dad3518999fcb39ad
4
- data.tar.gz: 5556652e925b9d3081562849790252900e9a2b2493ca7f6eb8ae023d888ed38a
3
+ metadata.gz: 817eba65c55a5dea765ab8e80ee5542a1353741659c8a32ef4eb80e39f052dcb
4
+ data.tar.gz: 25a07bc63696b7ba27933c9724c0a5ada466dc7cd0f37350ae4c9a4a475afbec
5
5
  SHA512:
6
- metadata.gz: 7bae7c856ed3b6c8c804c614e009a1efe36327c94cd8d1b5b48429b1fe849f75e99df68f1c85f719c63d57b05fd9584a707881bd01e8d232a5cf189bc9c7e69f
7
- data.tar.gz: 121f12dea70e459c11f7f91233fb7189dedf92bdc0ad8665063c427df67456a8bf0d0bfa035dec43f46919b851fad078bf48598cdac323ff2c86a02102b560f4
6
+ metadata.gz: c3d26bcc8f91f799f455f051109933875545219b14e9556cc4d5774dcda16e9abdcb1f0e6a090f1d9aea35c49d4d7f5ed8c6bae2b1e47a76cc75a86270e47cd7
7
+ data.tar.gz: 50a575b3666d1d6df0a8813a9761345ced5d895b2c73bf80347d8fb24e36c396389d4901fa22a6f34e1adcea6cb4d5b697bdab121dc495603da88740753e821d
@@ -22,7 +22,8 @@ module Coradoc
22
22
  # - "|" separates cells within the table
23
23
 
24
24
  def block(n_deep = 3)
25
- (example_block(n_deep) |
25
+ (markdown_code_block(n_deep) |
26
+ example_block(n_deep) |
26
27
  sidebar_block(n_deep) |
27
28
  source_block(n_deep) |
28
29
  quote_block(n_deep) |
@@ -60,6 +61,38 @@ module Coradoc
60
61
  block_style_exact(n_deep, '-', 2)
61
62
  end
62
63
 
64
+ # Markdown-style fenced code block: triple-backtick (or longer)
65
+ # fence with an optional language tag on the opening line. Behaves
66
+ # as a verbatim source block — same model as `[source,lang]\n----`.
67
+ # Pragmatic permissiveness for content that originates from (or is
68
+ # edited alongside) Markdown; not standard AsciiDoc but widely
69
+ # accepted (GitHub's renderer treats ``` as a listing delimiter).
70
+ def markdown_code_block(n_deep = 3)
71
+ capture_key = :"md_fence_#{n_deep}"
72
+ opening_fence = str('`').repeat(3).capture(capture_key)
73
+ closing_fence = dynamic do |_s, c|
74
+ str(c.captures[capture_key].to_s.strip)
75
+ end
76
+ language = (space? >> match("[A-Za-z0-9_+.-]").repeat(1).as(:language)).maybe
77
+
78
+ block_content_with_closing = dynamic do |_s, c|
79
+ fence_str = c.captures[capture_key].to_s.strip
80
+ closing_pattern = closing_fence >> space? >> newline
81
+
82
+ content = text_line(false, unguarded: true, verbatim: true) |
83
+ empty_line.as(:line_break)
84
+
85
+ (closing_pattern.absent? >> content).repeat(1)
86
+ end
87
+
88
+ block_header >>
89
+ line_start? >>
90
+ opening_fence.as(:delimiter) >> language >> newline >>
91
+ block_content_with_closing.as(:lines) >>
92
+ line_start? >>
93
+ closing_fence >> space? >> newline
94
+ end
95
+
63
96
  def block_title
64
97
  (line_start? >> block_delimiter.absent?) >>
65
98
  str('.') >> space.absent? >> text.as(:title) >> newline
@@ -80,8 +113,9 @@ module Coradoc
80
113
  c.repeat(1)
81
114
  end
82
115
 
83
- # Block delimiter: 4+ identical characters (or 2 for open block)
84
- # Used by paragraph.rb to reject lines that look like block delimiters.
116
+ # Block delimiter: 4+ identical characters, or 2 dashes for open
117
+ # blocks, or 3+ backticks for Markdown-style code fences. Used by
118
+ # paragraph.rb to reject lines that look like block delimiters.
85
119
  # NOTE: repeat(4,) means 4 or more (not exactly 4)
86
120
  def block_delimiter
87
121
  line_start? >>
@@ -91,7 +125,8 @@ module Coradoc
91
125
  str('+') |
92
126
  str('.') |
93
127
  str('-')).repeat(4) | # 4+ characters for most blocks
94
- str('-').repeat(2, 2)) >> # Exactly 2 for open block
128
+ str('-').repeat(2, 2) | # Exactly 2 for open block
129
+ str('`').repeat(3)) >> # 3+ for Markdown code fences
95
130
  newline
96
131
  end
97
132
 
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Transform
6
+ module ElementTransformers
7
+ # Transforms AsciiDoc {Model::Include} into the canonical
8
+ # {CoreModel::Include}. The CoreModel node carries the parsed
9
+ # options as a typed {CoreModel::IncludeOptions} instance plus
10
+ # the raw bracket body for verbatim round-trip.
11
+ class IncludeTransformer
12
+ class << self
13
+ # @param model [Coradoc::AsciiDoc::Model::Include]
14
+ # @return [Coradoc::CoreModel::Include]
15
+ def transform_include(model)
16
+ options_hash = extract_options_hash(model.attributes)
17
+ options = CoreModel::IncludeOptions.from_hash(options_hash)
18
+ raw = extract_raw_options(model.attributes)
19
+
20
+ CoreModel::Include.new(
21
+ target: model.path.to_s,
22
+ options: options,
23
+ raw_options: raw,
24
+ line_break: model.line_break.to_s
25
+ )
26
+ end
27
+
28
+ private
29
+
30
+ def extract_options_hash(attrs)
31
+ return {} unless attrs.is_a?(Coradoc::AsciiDoc::Model::AttributeList)
32
+
33
+ attrs.named.each_with_object({}) do |attr, hash|
34
+ hash[attr.name.to_s] = serialize_named_value(attr.value)
35
+ end
36
+ end
37
+
38
+ def serialize_named_value(value)
39
+ case value
40
+ when Array then value.map(&:to_s).join(';')
41
+ else value.to_s
42
+ end
43
+ end
44
+
45
+ def extract_raw_options(attrs)
46
+ return '' unless attrs.is_a?(Coradoc::AsciiDoc::Model::AttributeList)
47
+
48
+ adoc = attrs.to_adoc(show_empty: false).to_s
49
+ adoc.gsub(/\A\[|\]\z/, '')
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -10,6 +10,7 @@ module Coradoc
10
10
  autoload :InlineTransformer, "#{__dir__}/element_transformers/inline_transformer"
11
11
  autoload :TableTransformer, "#{__dir__}/element_transformers/table_transformer"
12
12
  autoload :OtherTransformer, "#{__dir__}/element_transformers/other_transformer"
13
+ autoload :IncludeTransformer, "#{__dir__}/element_transformers/include_transformer"
13
14
  end
14
15
  end
15
16
  end
@@ -388,8 +388,51 @@ module Coradoc
388
388
  )
389
389
  end
390
390
 
391
+ def transform_include(include)
392
+ Coradoc::AsciiDoc::Model::Include.new(
393
+ path: include.target.to_s,
394
+ attributes: build_include_attributes(include),
395
+ line_break: include.line_break.to_s
396
+ )
397
+ end
398
+
391
399
  private
392
400
 
401
+ def build_include_attributes(include)
402
+ list = Coradoc::AsciiDoc::Model::AttributeList.new
403
+ options = include.options
404
+ return list if options.nil?
405
+
406
+ add_tag_attribute(list, options)
407
+ add_simple_attribute(list, 'lines', options.lines_spec)
408
+ add_leveloffset_attribute(list, options)
409
+ add_simple_attribute(list, 'indent', options.indent&.to_s)
410
+ add_simple_attribute(list, 'encoding', options.file_encoding)
411
+ list
412
+ end
413
+
414
+ def add_simple_attribute(list, name, value)
415
+ return if value.nil? || value.to_s.empty?
416
+
417
+ list.add_named(name, value.to_s)
418
+ end
419
+
420
+ def add_tag_attribute(list, options)
421
+ if options.tags_wildcard
422
+ list.add_named('tags', '*')
423
+ elsif options.tags_inverted
424
+ list.add_named('tags', '**')
425
+ elsif options.tags.any?
426
+ list.add_named('tags', options.tags.join(';'))
427
+ end
428
+ end
429
+
430
+ def add_leveloffset_attribute(list, options)
431
+ return if options.leveloffset.nil?
432
+
433
+ list.add_named('leveloffset', options.leveloffset.to_s)
434
+ end
435
+
393
436
  # If the first CoreModel child is a FrontmatterBlock, serialize
394
437
  # it to YAML text via Codec (single source of truth) and pop it
395
438
  # from the children list. Returns [remaining_children,
@@ -120,6 +120,11 @@ module Coradoc
120
120
  Coradoc::CoreModel::CommentLine,
121
121
  ->(model) { FromCoreModel.transform_comment_line(model) }
122
122
  )
123
+
124
+ Registry.register(
125
+ Coradoc::CoreModel::Include,
126
+ ->(model) { FromCoreModel.transform_include(model) }
127
+ )
123
128
  end
124
129
  end
125
130
  end
@@ -10,6 +10,7 @@ module Coradoc
10
10
  Inl = ElementTransformers::InlineTransformer
11
11
  Tbl = ElementTransformers::TableTransformer
12
12
  Oth = ElementTransformers::OtherTransformer
13
+ Inc = ElementTransformers::IncludeTransformer
13
14
 
14
15
  class << self
15
16
  def register_all!
@@ -231,8 +232,16 @@ module Coradoc
231
232
  ->(model) { Oth.transform_bibliography_entry(model) }
232
233
  )
233
234
 
234
- [
235
+ # Include directives become first-class CoreModel::Include nodes
236
+ # (link edges in a text graph). To splice their content inline,
237
+ # call +Coradoc.resolve_includes(doc, base_dir:)+ on the parsed
238
+ # document — that step is intentionally separate from parse.
239
+ Registry.register(
235
240
  Coradoc::AsciiDoc::Model::Include,
241
+ ->(model) { Inc.transform_include(model) }
242
+ )
243
+
244
+ [
236
245
  Coradoc::AsciiDoc::Model::Audio,
237
246
  Coradoc::AsciiDoc::Model::Video,
238
247
  Coradoc::AsciiDoc::Model::ContentList,
@@ -25,6 +25,10 @@ module Coradoc
25
25
  lines: lines,
26
26
  ordering: ordering
27
27
  }
28
+ # Markdown fences carry the language tag inline (```ruby);
29
+ # pass it through so the SourceCode classifier entry can set
30
+ # block.lang directly, which extract_block_language prefers.
31
+ opts[:lang] = block[:language].to_s if block.key?(:language) && !block[:language].nil?
28
32
  BlockTypeClassifier.classify(delimiter, opts, attribute_list)
29
33
  end
30
34
 
@@ -28,7 +28,15 @@ module Coradoc
28
28
  ['.', 4, nil, ->(opts, attrs) { Model::Block::Literal.new(**opts.merge(attributes: attrs)) }],
29
29
  ['_', 4, nil, ->(opts, attrs) { Model::Block::Quote.new(**opts.merge(attributes: attrs)) }],
30
30
  ['-', 4, nil, ->(opts, attrs) { Model::Block::SourceCode.new(**opts.merge(attributes: attrs)) }],
31
- ['-', 2, 2, ->(opts, attrs) { Model::Block::Open.new(**opts.merge(attributes: attrs)) }]
31
+ ['-', 2, 2, ->(opts, attrs) { Model::Block::Open.new(**opts.merge(attributes: attrs)) }],
32
+ # Markdown-style triple-backtick fence: behaves as a SourceCode
33
+ # block. The language tag parsed from the opening fence is passed
34
+ # through opts[:lang]; extract_block_language prefers block.lang.
35
+ ['`', 3, nil, ->(opts, attrs) {
36
+ model_opts = opts.merge(attributes: attrs, delimiter_char: '`')
37
+ model_opts[:lang] = opts[:lang] if opts.key?(:lang)
38
+ Model::Block::SourceCode.new(**model_opts)
39
+ }]
32
40
  ].freeze
33
41
 
34
42
  module_function
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Coradoc
4
4
  module AsciiDoc
5
- VERSION = '2.0.18'
5
+ VERSION = '2.0.19'
6
6
  end
7
7
  end
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.18
4
+ version: 2.0.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -319,6 +319,7 @@ files:
319
319
  - lib/coradoc/asciidoc/transform/element_transformers.rb
320
320
  - lib/coradoc/asciidoc/transform/element_transformers/block_transformer.rb
321
321
  - lib/coradoc/asciidoc/transform/element_transformers/document_transformer.rb
322
+ - lib/coradoc/asciidoc/transform/element_transformers/include_transformer.rb
322
323
  - lib/coradoc/asciidoc/transform/element_transformers/inline_transformer.rb
323
324
  - lib/coradoc/asciidoc/transform/element_transformers/list_transformer.rb
324
325
  - lib/coradoc/asciidoc/transform/element_transformers/other_transformer.rb