commonmarker-merge 7.0.0 → 7.1.3
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
- checksums.yaml.gz.sig +0 -0
- data/LICENSE.md +13 -0
- data/README.md +523 -0
- data/lib/commonmarker/merge/backend.rb +194 -0
- data/lib/commonmarker/merge/comment_tracker.rb +7 -0
- data/lib/commonmarker/merge/debug_logger.rb +26 -0
- data/lib/commonmarker/merge/file_analysis.rb +33 -0
- data/lib/commonmarker/merge/freeze_node.rb +7 -0
- data/lib/commonmarker/merge/partial_template_merger.rb +20 -0
- data/lib/commonmarker/merge/provider.rb +41 -0
- data/lib/commonmarker/merge/smart_merger.rb +56 -0
- data/lib/commonmarker/merge/version.rb +5 -3
- data/lib/commonmarker/merge.rb +85 -24
- data/lib/commonmarker-merge.rb +7 -1
- data/sig/commonmarker/merge.rbs +15 -0
- data.tar.gz.sig +0 -0
- metadata +261 -16
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Commonmarker
|
|
4
|
+
module Merge
|
|
5
|
+
# Commonmarker backend using the Commonmarker gem (comrak Rust parser)
|
|
6
|
+
#
|
|
7
|
+
# This backend wraps Commonmarker, a Ruby gem that provides bindings to
|
|
8
|
+
# comrak, a fast CommonMark-compliant Markdown parser written in Rust.
|
|
9
|
+
#
|
|
10
|
+
# @note This backend only parses Markdown source code
|
|
11
|
+
# @see https://github.com/gjtorikian/commonmarker Commonmarker gem
|
|
12
|
+
#
|
|
13
|
+
# @example Basic usage
|
|
14
|
+
# parser = TreeHaver::Parser.new
|
|
15
|
+
# parser.language = Commonmarker::Merge::Backend::Language.markdown
|
|
16
|
+
# tree = parser.parse(markdown_source)
|
|
17
|
+
# root = tree.root_node
|
|
18
|
+
# puts root.type # => "document"
|
|
19
|
+
module Backend
|
|
20
|
+
Markdown::Merge::BackendSupport.install!(
|
|
21
|
+
backend_module: self,
|
|
22
|
+
backend_name: :commonmarker,
|
|
23
|
+
gem_name: 'commonmarker',
|
|
24
|
+
require_path: 'commonmarker/merge'
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Commonmarker language wrapper
|
|
28
|
+
#
|
|
29
|
+
# Commonmarker only parses Markdown. This class exists for API compatibility.
|
|
30
|
+
#
|
|
31
|
+
# @example
|
|
32
|
+
# language = Commonmarker::Merge::Backend::Language.markdown
|
|
33
|
+
# parser.language = language
|
|
34
|
+
class Language < TreeHaver::Base::Language
|
|
35
|
+
# Create a new Commonmarker language instance
|
|
36
|
+
#
|
|
37
|
+
# @param name [Symbol] Language name (should be :markdown)
|
|
38
|
+
# @param options [Hash] Commonmarker parse options
|
|
39
|
+
def initialize(name = :markdown, options: {})
|
|
40
|
+
super(name, backend: :commonmarker, options: options)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class << self
|
|
44
|
+
# Create a Markdown language instance
|
|
45
|
+
#
|
|
46
|
+
# @param options [Hash] Commonmarker parse options
|
|
47
|
+
# @return [Language] Markdown language
|
|
48
|
+
def markdown(options: {})
|
|
49
|
+
new(:markdown, options: options)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Load language from library path (API compatibility)
|
|
53
|
+
#
|
|
54
|
+
# @param _path [String] Ignored - Commonmarker doesn't load external grammars
|
|
55
|
+
# @param symbol [String, nil] Ignored
|
|
56
|
+
# @param name [String, nil] Language name hint (defaults to :markdown)
|
|
57
|
+
# @return [Language] Markdown language
|
|
58
|
+
# @raise [TreeHaver::NotAvailable] if requested language is not Markdown
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
Markdown::Merge::BackendSupport.configure_markdown_only_language_class!(
|
|
62
|
+
self,
|
|
63
|
+
backend_label: 'Commonmarker'
|
|
64
|
+
)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Commonmarker parser wrapper
|
|
68
|
+
class Parser < TreeHaver::Base::Parser
|
|
69
|
+
# Parse Markdown source code
|
|
70
|
+
#
|
|
71
|
+
# @param source [String] Markdown source to parse
|
|
72
|
+
# @return [Tree] Parsed tree
|
|
73
|
+
def parse(source)
|
|
74
|
+
raise 'Language not set' unless language
|
|
75
|
+
|
|
76
|
+
Backend.available? or raise 'Commonmarker not available'
|
|
77
|
+
|
|
78
|
+
opts = language.options || {}
|
|
79
|
+
doc = ::Commonmarker.parse(source, options: opts)
|
|
80
|
+
Tree.new(doc, source)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Commonmarker node wrapper
|
|
85
|
+
#
|
|
86
|
+
# Wraps Commonmarker::Node to provide TreeHaver::Node-compatible interface.
|
|
87
|
+
class Node < TreeHaver::Base::Node
|
|
88
|
+
Markdown::Merge::BackendSupport.configure_node_link_and_navigation!(
|
|
89
|
+
self,
|
|
90
|
+
next_sibling_selector: :next_sibling,
|
|
91
|
+
prev_sibling_selector: :previous_sibling
|
|
92
|
+
)
|
|
93
|
+
Markdown::Merge::BackendSupport.configure_node_heading_and_code_block_helpers!(
|
|
94
|
+
self,
|
|
95
|
+
heading_matcher: ->(node) { node.type == 'heading' },
|
|
96
|
+
code_block_matcher: ->(node) { node.type == 'code_block' }
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Get the node type as a string
|
|
100
|
+
#
|
|
101
|
+
# @return [String] Node type
|
|
102
|
+
def type
|
|
103
|
+
inner_node.type.to_s
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Alias for TreeHaver compatibility
|
|
107
|
+
alias kind type
|
|
108
|
+
|
|
109
|
+
# Get the text content of this node
|
|
110
|
+
#
|
|
111
|
+
# @return [String] Node text
|
|
112
|
+
def text
|
|
113
|
+
if inner_node.respond_to?(:string_content)
|
|
114
|
+
begin
|
|
115
|
+
content = inner_node.string_content.to_s
|
|
116
|
+
return content unless content.empty?
|
|
117
|
+
rescue TypeError
|
|
118
|
+
# Container node - fall through
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
children.map(&:text).join
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Get child nodes
|
|
125
|
+
#
|
|
126
|
+
# @return [Array<Node>] Child nodes
|
|
127
|
+
def children
|
|
128
|
+
return [] unless inner_node.respond_to?(:each)
|
|
129
|
+
|
|
130
|
+
result = []
|
|
131
|
+
inner_node.each { |child| result << Node.new(child, source: source, lines: lines) }
|
|
132
|
+
result
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Get start byte offset
|
|
136
|
+
def start_byte
|
|
137
|
+
sp = start_point
|
|
138
|
+
calculate_byte_offset(sp[:row], sp[:column])
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Get end byte offset
|
|
142
|
+
def end_byte
|
|
143
|
+
ep = end_point
|
|
144
|
+
calculate_byte_offset(ep[:row], ep[:column])
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Get start point (0-based row/column)
|
|
148
|
+
# @return [Point] Start position
|
|
149
|
+
def start_point
|
|
150
|
+
if inner_node.respond_to?(:source_position)
|
|
151
|
+
begin
|
|
152
|
+
pos = inner_node.source_position
|
|
153
|
+
return Point.new(pos[:start_line] - 1, (pos[:start_column] || 1) - 1) if pos && pos[:start_line]
|
|
154
|
+
rescue StandardError
|
|
155
|
+
nil
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Fallback: check sourcepos (old API)
|
|
160
|
+
begin
|
|
161
|
+
pos = inner_node.sourcepos
|
|
162
|
+
return Point.new(pos[0] - 1, pos[1] - 1) if pos
|
|
163
|
+
rescue StandardError
|
|
164
|
+
nil
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
Point.new(0, 0)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Get end point (0-based row/column)
|
|
171
|
+
# @return [Point] End position
|
|
172
|
+
def end_point
|
|
173
|
+
if inner_node.respond_to?(:source_position)
|
|
174
|
+
begin
|
|
175
|
+
pos = inner_node.source_position
|
|
176
|
+
return Point.new(pos[:end_line] - 1, (pos[:end_column] || 1) - 1) if pos && pos[:end_line]
|
|
177
|
+
rescue StandardError
|
|
178
|
+
nil
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
begin
|
|
183
|
+
pos = inner_node.sourcepos
|
|
184
|
+
return Point.new(pos[2] - 1, pos[3] - 1) if pos
|
|
185
|
+
rescue StandardError
|
|
186
|
+
nil
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
Point.new(0, 0)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Commonmarker
|
|
4
|
+
module Merge
|
|
5
|
+
# Debug logging utility for Commonmarker::Merge operations.
|
|
6
|
+
#
|
|
7
|
+
# Extends Ast::Merge::DebugLogger to provide consistent logging
|
|
8
|
+
# across all merge gems. Logs are controlled via environment variables.
|
|
9
|
+
#
|
|
10
|
+
# @example Enable debug logging
|
|
11
|
+
# ENV["COMMONMARKER_MERGE_DEBUG"] = "1"
|
|
12
|
+
# DebugLogger.debug("Parsing markdown", { file: "README.md" })
|
|
13
|
+
#
|
|
14
|
+
# @example Time an operation
|
|
15
|
+
# result = DebugLogger.time("parse") { Commonmarker.parse(source) }
|
|
16
|
+
#
|
|
17
|
+
# @see Ast::Merge::DebugLogger Base module
|
|
18
|
+
module DebugLogger
|
|
19
|
+
Markdown::Merge::WrapperSupport.configure_debug_logger!(
|
|
20
|
+
debug_logger_module: self,
|
|
21
|
+
env_var_name: 'COMMONMARKER_MERGE_DEBUG',
|
|
22
|
+
log_prefix: '[commonmarker-merge]'
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Commonmarker
|
|
4
|
+
module Merge
|
|
5
|
+
# File analysis for Markdown files using CommonMarker.
|
|
6
|
+
#
|
|
7
|
+
# This is a thin wrapper around Markdown::Merge::FileAnalysis that:
|
|
8
|
+
# - Forces the :commonmarker backend
|
|
9
|
+
# - Sets the default freeze token to "commonmarker-merge"
|
|
10
|
+
# - Exposes commonmarker-specific options
|
|
11
|
+
#
|
|
12
|
+
# @example Basic usage
|
|
13
|
+
# analysis = FileAnalysis.new(markdown_source)
|
|
14
|
+
# analysis.statements.each do |node|
|
|
15
|
+
# puts "#{node.merge_type}: #{node.type}"
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# @example With custom freeze token
|
|
19
|
+
# analysis = FileAnalysis.new(source, freeze_token: "my-merge")
|
|
20
|
+
#
|
|
21
|
+
# @see Markdown::Merge::FileAnalysis Underlying implementation
|
|
22
|
+
class FileAnalysis < Markdown::Merge::FileAnalysis
|
|
23
|
+
# Default freeze token for commonmarker-merge
|
|
24
|
+
# @return [String]
|
|
25
|
+
DEFAULT_FREEZE_TOKEN = 'commonmarker-merge'
|
|
26
|
+
|
|
27
|
+
Markdown::Merge::WrapperSupport.configure_file_analysis_subclass!(
|
|
28
|
+
self,
|
|
29
|
+
default_backend: :commonmarker
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Commonmarker
|
|
4
|
+
module Merge
|
|
5
|
+
# Thin Commonmarker-specific wrapper for Markdown::Merge::PartialTemplateMerger.
|
|
6
|
+
#
|
|
7
|
+
# Forces the :commonmarker backend while inheriting comment-handling and
|
|
8
|
+
# merge behavior from markdown-merge.
|
|
9
|
+
class PartialTemplateMerger < Markdown::Merge::PartialTemplateMerger
|
|
10
|
+
Result = Markdown::Merge::PartialTemplateMerger::Result
|
|
11
|
+
|
|
12
|
+
Markdown::Merge::WrapperSupport.configure_partial_template_merger_subclass!(
|
|
13
|
+
self,
|
|
14
|
+
default_backend: :commonmarker,
|
|
15
|
+
file_analysis_class: -> { FileAnalysis },
|
|
16
|
+
smart_merger_class: -> { SmartMerger }
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Commonmarker
|
|
4
|
+
# Source-preserving Markdown provider integration for Commonmarker.
|
|
5
|
+
module Merge
|
|
6
|
+
# Native Commonmarker backend configuration for the shared provider engine.
|
|
7
|
+
class Provider < Markdown::Merge::SourcePreservingProvider
|
|
8
|
+
# rubocop:disable Metrics/MethodLength -- constructor declares the complete backend boundary
|
|
9
|
+
def initialize
|
|
10
|
+
super(
|
|
11
|
+
provider_id: 'ruby.markdown.commonmarker',
|
|
12
|
+
role: :backend,
|
|
13
|
+
backend: Markdown::Merge::ProviderBackend.new(
|
|
14
|
+
id: :commonmarker,
|
|
15
|
+
package: PACKAGE_NAME,
|
|
16
|
+
dialects: %i[markdown commonmark],
|
|
17
|
+
parser: lambda { |source|
|
|
18
|
+
parser = Backend::Parser.new
|
|
19
|
+
parser.language = Backend::Language.markdown
|
|
20
|
+
parser.parse(source)
|
|
21
|
+
},
|
|
22
|
+
headings: Markdown::Merge::ProviderBackend.method(:native_headings)
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
# rubocop:enable Metrics/MethodLength
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class << self
|
|
30
|
+
def merge_provider
|
|
31
|
+
@merge_provider ||= Provider.new
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def register_provider!(replace: false)
|
|
35
|
+
return unless Ast::Merge.respond_to?(:register_provider)
|
|
36
|
+
|
|
37
|
+
Ast::Merge.register_provider(merge_provider, replace: replace)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Commonmarker
|
|
4
|
+
module Merge
|
|
5
|
+
# Orchestrates the smart merge process for Markdown files using CommonMarker.
|
|
6
|
+
#
|
|
7
|
+
# This is a thin wrapper around Markdown::Merge::SmartMerger that:
|
|
8
|
+
# - Forces the :commonmarker backend
|
|
9
|
+
# - Sets commonmarker-specific defaults (freeze token, inner_merge_code_blocks)
|
|
10
|
+
# - Exposes commonmarker-specific options (options hash)
|
|
11
|
+
#
|
|
12
|
+
# @example Basic merge (destination customizations preserved)
|
|
13
|
+
# merger = SmartMerger.new(template_content, dest_content)
|
|
14
|
+
# result = merger.merge
|
|
15
|
+
# if result.success?
|
|
16
|
+
# File.write("output.md", result.content)
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# @example Template updates win
|
|
20
|
+
# merger = SmartMerger.new(
|
|
21
|
+
# template_content,
|
|
22
|
+
# dest_content,
|
|
23
|
+
# preference: :template,
|
|
24
|
+
# add_template_only_nodes: true
|
|
25
|
+
# )
|
|
26
|
+
# result = merger.merge
|
|
27
|
+
#
|
|
28
|
+
# @example Custom signature matching
|
|
29
|
+
# sig_gen = ->(node) {
|
|
30
|
+
# canonical_type = Ast::Merge::NodeTyping.merge_type_for(node) || node.type
|
|
31
|
+
# if canonical_type == :heading
|
|
32
|
+
# [:heading, node.header_level] # Match by level only, not content
|
|
33
|
+
# else
|
|
34
|
+
# node # Fall through to default
|
|
35
|
+
# end
|
|
36
|
+
# }
|
|
37
|
+
# merger = SmartMerger.new(
|
|
38
|
+
# template_content,
|
|
39
|
+
# dest_content,
|
|
40
|
+
# signature_generator: sig_gen
|
|
41
|
+
# )
|
|
42
|
+
#
|
|
43
|
+
# @see Markdown::Merge::SmartMerger Underlying implementation
|
|
44
|
+
class SmartMerger < Markdown::Merge::SmartMerger
|
|
45
|
+
Markdown::Merge::WrapperSupport.configure_smart_merger_subclass!(
|
|
46
|
+
self,
|
|
47
|
+
default_backend: :commonmarker,
|
|
48
|
+
default_freeze_token: -> { DEFAULT_FREEZE_TOKEN },
|
|
49
|
+
default_inner_merge_code_blocks: -> { DEFAULT_INNER_MERGE_CODE_BLOCKS },
|
|
50
|
+
file_analysis_class: -> { FileAnalysis },
|
|
51
|
+
template_parse_error_class: -> { TemplateParseError },
|
|
52
|
+
destination_parse_error_class: -> { DestinationParseError }
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module Commonmarker
|
|
4
4
|
module Merge
|
|
5
|
+
# Version namespace for this gem.
|
|
5
6
|
module Version
|
|
6
|
-
|
|
7
|
+
# Current gem version.
|
|
8
|
+
VERSION = '7.1.3'
|
|
7
9
|
end
|
|
8
|
-
|
|
9
|
-
VERSION = Version::VERSION
|
|
10
|
+
# Current gem version exposed at the traditional constant location.
|
|
11
|
+
VERSION = Version::VERSION # Traditional Constant Location
|
|
10
12
|
end
|
|
11
13
|
end
|
data/lib/commonmarker/merge.rb
CHANGED
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require 'markdown-merge'
|
|
4
|
+
require 'commonmarker'
|
|
5
|
+
require_relative 'merge/version'
|
|
6
|
+
require_relative 'merge/backend'
|
|
5
7
|
|
|
6
8
|
module Commonmarker
|
|
7
9
|
module Merge
|
|
8
|
-
|
|
10
|
+
module_function
|
|
9
11
|
|
|
10
|
-
PACKAGE_NAME =
|
|
11
|
-
BACKEND_REFERENCE = TreeHaver::BackendReference.new(id:
|
|
12
|
+
PACKAGE_NAME = 'commonmarker-merge'
|
|
13
|
+
BACKEND_REFERENCE = TreeHaver::BackendReference.new(id: 'commonmarker', family: 'native').freeze
|
|
12
14
|
TreeHaver::BackendRegistry.register(BACKEND_REFERENCE)
|
|
15
|
+
Markdown::Merge::WrapperSupport.install!(
|
|
16
|
+
wrapper_module: self,
|
|
17
|
+
require_prefix: 'commonmarker/merge',
|
|
18
|
+
default_freeze_token: 'commonmarker-merge',
|
|
19
|
+
default_inner_merge_code_blocks: false,
|
|
20
|
+
registry_tag: :commonmarker_merge,
|
|
21
|
+
merger_class: 'Commonmarker::Merge::SmartMerger'
|
|
22
|
+
)
|
|
13
23
|
|
|
14
24
|
def markdown_feature_profile
|
|
15
25
|
Markdown::Merge.markdown_feature_profile
|
|
@@ -21,7 +31,9 @@ module Commonmarker
|
|
|
21
31
|
|
|
22
32
|
def markdown_backend_feature_profile(backend: nil)
|
|
23
33
|
requested = backend.to_s.empty? ? BACKEND_REFERENCE.id : backend.to_s
|
|
24
|
-
|
|
34
|
+
unless requested == BACKEND_REFERENCE.id
|
|
35
|
+
return unsupported_feature_result("Unsupported Markdown backend #{requested}.")
|
|
36
|
+
end
|
|
25
37
|
|
|
26
38
|
markdown_feature_profile.merge(backend: BACKEND_REFERENCE.id, backend_ref: BACKEND_REFERENCE.to_h)
|
|
27
39
|
end
|
|
@@ -42,18 +54,20 @@ module Commonmarker
|
|
|
42
54
|
|
|
43
55
|
def parse_markdown(source, dialect, backend: nil)
|
|
44
56
|
requested = backend.to_s.empty? ? BACKEND_REFERENCE.id : backend.to_s
|
|
45
|
-
|
|
57
|
+
unless requested == BACKEND_REFERENCE.id
|
|
58
|
+
return unsupported_feature_result("Unsupported Markdown backend #{requested}.")
|
|
59
|
+
end
|
|
46
60
|
|
|
47
|
-
|
|
61
|
+
TreeHaver.with_backend(BACKEND_REFERENCE.id) { TreeHaver.parser_for(:markdown).parse(source) }
|
|
48
62
|
normalized = Markdown::Merge.normalize_source(source)
|
|
49
63
|
{
|
|
50
64
|
ok: true,
|
|
51
65
|
diagnostics: [],
|
|
52
66
|
analysis: {
|
|
53
|
-
kind:
|
|
67
|
+
kind: 'markdown',
|
|
54
68
|
dialect: dialect,
|
|
55
69
|
normalized_source: normalized,
|
|
56
|
-
root_kind:
|
|
70
|
+
root_kind: 'document',
|
|
57
71
|
owners: Markdown::Merge.collect_markdown_owners(normalized)
|
|
58
72
|
},
|
|
59
73
|
policies: []
|
|
@@ -61,7 +75,7 @@ module Commonmarker
|
|
|
61
75
|
rescue StandardError => e
|
|
62
76
|
{
|
|
63
77
|
ok: false,
|
|
64
|
-
diagnostics: [{ severity:
|
|
78
|
+
diagnostics: [{ severity: 'error', category: 'parse_error', message: e.message }],
|
|
65
79
|
policies: []
|
|
66
80
|
}
|
|
67
81
|
end
|
|
@@ -72,14 +86,44 @@ module Commonmarker
|
|
|
72
86
|
|
|
73
87
|
def merge_markdown(template_source, destination_source, dialect, backend: nil)
|
|
74
88
|
requested = backend.to_s.empty? ? BACKEND_REFERENCE.id : backend.to_s
|
|
75
|
-
|
|
89
|
+
unless requested == BACKEND_REFERENCE.id
|
|
90
|
+
return unsupported_feature_result("Unsupported Markdown backend #{requested}.")
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
template = parse_markdown(template_source, dialect, backend: backend)
|
|
94
|
+
return template unless template[:ok]
|
|
76
95
|
|
|
77
|
-
|
|
96
|
+
destination = parse_markdown(destination_source, dialect, backend: backend)
|
|
97
|
+
return destination unless destination[:ok]
|
|
98
|
+
|
|
99
|
+
destination_sections = Markdown::Merge.collect_markdown_sections(
|
|
100
|
+
destination.dig(:analysis, :normalized_source),
|
|
101
|
+
destination.dig(:analysis, :owners)
|
|
102
|
+
)
|
|
103
|
+
template_sections = Markdown::Merge.collect_markdown_sections(
|
|
104
|
+
template.dig(:analysis, :normalized_source),
|
|
105
|
+
template.dig(:analysis, :owners)
|
|
106
|
+
)
|
|
107
|
+
destination_paths = destination_sections.to_h { |section| [section[:path], true] }
|
|
108
|
+
merged_sections = destination_sections.map { |section| section[:text] }.reject(&:empty?) +
|
|
109
|
+
template_sections
|
|
110
|
+
.reject { |section| destination_paths[section[:path]] || section[:text].empty? }
|
|
111
|
+
.map { |section| section[:text] }
|
|
112
|
+
|
|
113
|
+
{
|
|
114
|
+
ok: true,
|
|
115
|
+
diagnostics: [],
|
|
116
|
+
output: "#{merged_sections.join("\n\n").strip}\n",
|
|
117
|
+
policies: []
|
|
118
|
+
}
|
|
78
119
|
end
|
|
79
120
|
|
|
80
|
-
def merge_markdown_with_reviewed_nested_outputs(template_source, destination_source, dialect, review_state,
|
|
121
|
+
def merge_markdown_with_reviewed_nested_outputs(template_source, destination_source, dialect, review_state,
|
|
122
|
+
applied_children, backend: nil)
|
|
81
123
|
requested = backend.to_s.empty? ? BACKEND_REFERENCE.id : backend.to_s
|
|
82
|
-
|
|
124
|
+
unless requested == BACKEND_REFERENCE.id
|
|
125
|
+
return unsupported_feature_result("Unsupported Markdown backend #{requested}.")
|
|
126
|
+
end
|
|
83
127
|
|
|
84
128
|
Markdown::Merge.merge_markdown_with_reviewed_nested_outputs(
|
|
85
129
|
template_source,
|
|
@@ -90,9 +134,12 @@ module Commonmarker
|
|
|
90
134
|
)
|
|
91
135
|
end
|
|
92
136
|
|
|
93
|
-
def merge_markdown_with_reviewed_nested_outputs_from_replay_bundle(template_source, destination_source, dialect,
|
|
137
|
+
def merge_markdown_with_reviewed_nested_outputs_from_replay_bundle(template_source, destination_source, dialect,
|
|
138
|
+
replay_bundle, backend: nil)
|
|
94
139
|
requested = backend.to_s.empty? ? BACKEND_REFERENCE.id : backend.to_s
|
|
95
|
-
|
|
140
|
+
unless requested == BACKEND_REFERENCE.id
|
|
141
|
+
return unsupported_feature_result("Unsupported Markdown backend #{requested}.")
|
|
142
|
+
end
|
|
96
143
|
|
|
97
144
|
Markdown::Merge.merge_markdown_with_reviewed_nested_outputs_from_replay_bundle(
|
|
98
145
|
template_source,
|
|
@@ -102,9 +149,12 @@ module Commonmarker
|
|
|
102
149
|
)
|
|
103
150
|
end
|
|
104
151
|
|
|
105
|
-
def merge_markdown_with_reviewed_nested_outputs_from_replay_bundle_envelope(template_source, destination_source,
|
|
152
|
+
def merge_markdown_with_reviewed_nested_outputs_from_replay_bundle_envelope(template_source, destination_source,
|
|
153
|
+
dialect, envelope, backend: nil)
|
|
106
154
|
requested = backend.to_s.empty? ? BACKEND_REFERENCE.id : backend.to_s
|
|
107
|
-
|
|
155
|
+
unless requested == BACKEND_REFERENCE.id
|
|
156
|
+
return unsupported_feature_result("Unsupported Markdown backend #{requested}.")
|
|
157
|
+
end
|
|
108
158
|
|
|
109
159
|
Markdown::Merge.merge_markdown_with_reviewed_nested_outputs_from_replay_bundle_envelope(
|
|
110
160
|
template_source,
|
|
@@ -114,9 +164,12 @@ module Commonmarker
|
|
|
114
164
|
)
|
|
115
165
|
end
|
|
116
166
|
|
|
117
|
-
def merge_markdown_with_reviewed_nested_outputs_from_review_state(template_source, destination_source, dialect,
|
|
167
|
+
def merge_markdown_with_reviewed_nested_outputs_from_review_state(template_source, destination_source, dialect,
|
|
168
|
+
review_state, backend: nil)
|
|
118
169
|
requested = backend.to_s.empty? ? BACKEND_REFERENCE.id : backend.to_s
|
|
119
|
-
|
|
170
|
+
unless requested == BACKEND_REFERENCE.id
|
|
171
|
+
return unsupported_feature_result("Unsupported Markdown backend #{requested}.")
|
|
172
|
+
end
|
|
120
173
|
|
|
121
174
|
Markdown::Merge.merge_markdown_with_reviewed_nested_outputs_from_review_state(
|
|
122
175
|
template_source,
|
|
@@ -126,9 +179,12 @@ module Commonmarker
|
|
|
126
179
|
)
|
|
127
180
|
end
|
|
128
181
|
|
|
129
|
-
def merge_markdown_with_reviewed_nested_outputs_from_review_state_envelope(template_source, destination_source,
|
|
182
|
+
def merge_markdown_with_reviewed_nested_outputs_from_review_state_envelope(template_source, destination_source,
|
|
183
|
+
dialect, envelope, backend: nil)
|
|
130
184
|
requested = backend.to_s.empty? ? BACKEND_REFERENCE.id : backend.to_s
|
|
131
|
-
|
|
185
|
+
unless requested == BACKEND_REFERENCE.id
|
|
186
|
+
return unsupported_feature_result("Unsupported Markdown backend #{requested}.")
|
|
187
|
+
end
|
|
132
188
|
|
|
133
189
|
Markdown::Merge.merge_markdown_with_reviewed_nested_outputs_from_review_state_envelope(
|
|
134
190
|
template_source,
|
|
@@ -145,7 +201,7 @@ module Commonmarker
|
|
|
145
201
|
def unsupported_feature_result(message)
|
|
146
202
|
{
|
|
147
203
|
ok: false,
|
|
148
|
-
diagnostics: [{ severity:
|
|
204
|
+
diagnostics: [{ severity: 'error', category: 'unsupported_feature', message: message }],
|
|
149
205
|
policies: []
|
|
150
206
|
}
|
|
151
207
|
end
|
|
@@ -168,3 +224,8 @@ module Commonmarker
|
|
|
168
224
|
)
|
|
169
225
|
end
|
|
170
226
|
end
|
|
227
|
+
|
|
228
|
+
require_relative 'merge/provider'
|
|
229
|
+
Commonmarker::Merge.register_provider!
|
|
230
|
+
|
|
231
|
+
Commonmarker::Merge.ensure_backend_loaded!
|
data/lib/commonmarker-merge.rb
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative
|
|
3
|
+
require_relative 'commonmarker/merge'
|
|
4
|
+
require 'version_gem'
|
|
5
|
+
require_relative 'commonmarker/merge/version'
|
|
6
|
+
|
|
7
|
+
Commonmarker::Merge::Version.class_eval do
|
|
8
|
+
extend VersionGem::Basic
|
|
9
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Commonmarker
|
|
2
|
+
module Merge
|
|
3
|
+
module Version
|
|
4
|
+
VERSION: String
|
|
5
|
+
end
|
|
6
|
+
VERSION: String
|
|
7
|
+
|
|
8
|
+
class Provider < Markdown::Merge::SourcePreservingProvider
|
|
9
|
+
def initialize: () -> void
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.merge_provider: () -> Provider
|
|
13
|
+
def self.register_provider!: (?replace: bool) -> untyped
|
|
14
|
+
end
|
|
15
|
+
end
|
data.tar.gz.sig
CHANGED
|
Binary file
|