marlens-jira-api 0.6.0 → 0.7.0
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/README.md +8 -0
- data/lib/marlens/jira_api/adf_to_markdown.rb +152 -0
- data/lib/marlens/jira_api/version.rb +1 -1
- data/lib/marlens/jira_api.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '08ccc21d16f1e2593da0304416dabc4e08b0d60891b2fcf05f03ccc249244081'
|
|
4
|
+
data.tar.gz: 551652ac549e8034ec3633b9b42db59c6ddf3e44485b8b15b602286f8bf9c525
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bb82c632c653f9d421849d2d217d3560173a04a4235f0322b243862cadb1658f1ea4dd1d9afca7ea191a7f013112c04f51f91f1e589d0e1ce19ad6abd4ec6ac3
|
|
7
|
+
data.tar.gz: 38def1ee536eba0d1fd8b4283f961737bc0c26ac0e10af78b6fb886372f574f29c0a28359c5dd697ff2f475d8ebddee27eb993a872b3e3ca3bc412d163f0b9a6
|
data/README.md
CHANGED
|
@@ -39,6 +39,14 @@ client.update_markdown_comment(
|
|
|
39
39
|
client.delete_comment(issue_key: "WRAPX-123", comment_id: created.fetch("id"))
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
### ADF to Markdown
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
markdown = Marlens::JiraApi::AdfToMarkdown.call(issue.fetch("fields").fetch("description"))
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Supports ADF documents, paragraphs, headings, block quotes, ordered and bullet lists, list items, text, and strong, emphasis, code, link, and strike marks. Unsupported nodes preserve traversable `content`; nodes without traversable content render nothing.
|
|
49
|
+
|
|
42
50
|
### Read errors
|
|
43
51
|
|
|
44
52
|
`get_issue` and `list_remote_links` return parsed Jira JSON. A non-2xx response raises `RuntimeError` with the HTTP method, request path, status, and response body. A successful response with malformed JSON raises `JSON::ParserError`.
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Marlens
|
|
4
|
+
module JiraApi
|
|
5
|
+
class AdfToMarkdown
|
|
6
|
+
BLOCK_TYPES = %w[doc paragraph heading blockquote orderedList bulletList listItem].freeze
|
|
7
|
+
|
|
8
|
+
def self.call(document)
|
|
9
|
+
new(document).to_markdown
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def initialize(document)
|
|
13
|
+
@document = document.is_a?(Hash) ? document : {}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_markdown
|
|
17
|
+
render_block(@document).strip
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def render_block(node)
|
|
23
|
+
case node["type"]
|
|
24
|
+
when "doc"
|
|
25
|
+
render_blocks(children(node)).join("\n\n")
|
|
26
|
+
when "paragraph"
|
|
27
|
+
render_inline_nodes(children(node))
|
|
28
|
+
when "heading"
|
|
29
|
+
"#{"#" * heading_level(node)} #{render_inline_nodes(children(node))}".rstrip
|
|
30
|
+
when "blockquote"
|
|
31
|
+
quote(render_blocks(children(node)).join("\n\n"))
|
|
32
|
+
when "orderedList", "bulletList"
|
|
33
|
+
render_list(node)
|
|
34
|
+
when "listItem"
|
|
35
|
+
render_list_item(node, marker: "-", indent: 0)
|
|
36
|
+
when "text", "hardBreak"
|
|
37
|
+
render_inline(node)
|
|
38
|
+
else
|
|
39
|
+
render_unknown(node)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def render_blocks(nodes)
|
|
44
|
+
nodes.filter_map do |node|
|
|
45
|
+
rendered = render_block(node)
|
|
46
|
+
rendered unless rendered.empty?
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def render_unknown(node)
|
|
51
|
+
content = children(node)
|
|
52
|
+
return "" if content.empty?
|
|
53
|
+
|
|
54
|
+
if content.any? { |child| BLOCK_TYPES.include?(child["type"]) }
|
|
55
|
+
render_blocks(content).join("\n\n")
|
|
56
|
+
else
|
|
57
|
+
render_inline_nodes(content)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def render_list(node, indent: 0)
|
|
62
|
+
start = node.dig("attrs", "order").to_i
|
|
63
|
+
start = 1 if start.zero?
|
|
64
|
+
|
|
65
|
+
children(node).each_with_index.map do |item, index|
|
|
66
|
+
marker = node["type"] == "orderedList" ? "#{start + index}." : "-"
|
|
67
|
+
render_list_item(item, marker:, indent:)
|
|
68
|
+
end.join("\n")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def render_list_item(node, marker:, indent:)
|
|
72
|
+
item_children = children(node)
|
|
73
|
+
first_child = item_children.shift
|
|
74
|
+
indentation = " " * indent
|
|
75
|
+
prefix = "#{marker} "
|
|
76
|
+
|
|
77
|
+
if first_child&.fetch("type", nil) == "paragraph"
|
|
78
|
+
lines = ["#{indentation}#{prefix}#{render_inline_nodes(children(first_child))}".rstrip]
|
|
79
|
+
else
|
|
80
|
+
lines = ["#{indentation}#{marker}"]
|
|
81
|
+
item_children.unshift(first_child) unless first_child.nil?
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
continuation_indent = indent + prefix.length
|
|
85
|
+
item_children.each do |child|
|
|
86
|
+
rendered = if ["orderedList", "bulletList"].include?(child["type"])
|
|
87
|
+
render_list(child, indent: continuation_indent)
|
|
88
|
+
else
|
|
89
|
+
indent_lines(render_block(child), continuation_indent)
|
|
90
|
+
end
|
|
91
|
+
lines << rendered unless rendered.empty?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
lines.join("\n")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def render_inline_nodes(nodes)
|
|
98
|
+
nodes.map { |node| render_inline(node) }.join
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def render_inline(node)
|
|
102
|
+
case node["type"]
|
|
103
|
+
when "text"
|
|
104
|
+
apply_marks(node.fetch("text", ""), node["marks"])
|
|
105
|
+
when "hardBreak"
|
|
106
|
+
"\n"
|
|
107
|
+
else
|
|
108
|
+
render_inline_nodes(children(node))
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def apply_marks(text, marks)
|
|
113
|
+
Array(marks).reduce(text) do |markdown, mark|
|
|
114
|
+
case mark["type"]
|
|
115
|
+
when "strong", "bold"
|
|
116
|
+
"**#{markdown}**"
|
|
117
|
+
when "em", "italic"
|
|
118
|
+
"*#{markdown}*"
|
|
119
|
+
when "code"
|
|
120
|
+
"`#{markdown}`"
|
|
121
|
+
when "link"
|
|
122
|
+
href = mark.dig("attrs", "href")
|
|
123
|
+
href.to_s.empty? ? markdown : "[#{markdown}](#{href})"
|
|
124
|
+
when "strike"
|
|
125
|
+
"~~#{markdown}~~"
|
|
126
|
+
else
|
|
127
|
+
markdown
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def heading_level(node)
|
|
133
|
+
level = node.dig("attrs", "level").to_i
|
|
134
|
+
level.zero? ? 1 : level
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def quote(content)
|
|
138
|
+
content.split("\n", -1).map { |line| line.empty? ? ">" : "> #{line}" }.join("\n")
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def indent_lines(text, indent)
|
|
142
|
+
return "" if text.empty?
|
|
143
|
+
|
|
144
|
+
text.lines(chomp: true).map { |line| "#{" " * indent}#{line}" }.join("\n")
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def children(node)
|
|
148
|
+
Array(node["content"]).select { |child| child.is_a?(Hash) }
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
data/lib/marlens/jira_api.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: marlens-jira-api
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Marlen Brunner
|
|
@@ -92,6 +92,7 @@ files:
|
|
|
92
92
|
- README.md
|
|
93
93
|
- bin/jira-comment
|
|
94
94
|
- lib/marlens/jira_api.rb
|
|
95
|
+
- lib/marlens/jira_api/adf_to_markdown.rb
|
|
95
96
|
- lib/marlens/jira_api/cli.rb
|
|
96
97
|
- lib/marlens/jira_api/client.rb
|
|
97
98
|
- lib/marlens/jira_api/markdown_to_adf.rb
|