notion_to_md 0.0.0 → 0.1.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 +45 -1
- data/lib/notion_to_md/block.rb +119 -0
- data/lib/notion_to_md/converter.rb +9 -125
- data/lib/notion_to_md/logger.rb +2 -6
- data/lib/notion_to_md/text.rb +13 -0
- data/lib/notion_to_md/text_annotation.rb +5 -3
- data/lib/notion_to_md/version.rb +1 -1
- data/lib/notion_to_md.rb +6 -0
- metadata +47 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77ebe548eec487347104eabbac6911836cef0ec6e5ea350cb9a376ef8e07ce50
|
4
|
+
data.tar.gz: b2fd0700b53683daa6e59a729418139bbdee41da8184dad57eff0f2c17578dc7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e7f09feec62553d76c72e670aa4fa05d02e98f19e74352237c8c42a255960570f77ae530b3196be24a054fa8a55f744f0b0b96dfbfb1c5e7d06f71b1423bcdf6
|
7
|
+
data.tar.gz: '09a041dab71e1fea3796ca9193c6a5fdf385de1d7fc212373f2e7cec086568935c72171ba900c90001907fdd4e1667e819b69c28740c2e5fa18a4b17821facb3'
|
data/README.md
CHANGED
@@ -1,2 +1,46 @@
|
|
1
1
|
# notion_to_md
|
2
|
-
Notion Markdown Exporter in Ruby
|
2
|
+
Notion Markdown Exporter in Ruby.
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
Use gem to install.
|
6
|
+
```bash
|
7
|
+
$ gem install 'notion_to_md'
|
8
|
+
```
|
9
|
+
|
10
|
+
Or add it to the `Gemfile`.
|
11
|
+
```ruby
|
12
|
+
# Gemfile
|
13
|
+
gem 'notion_to_md'
|
14
|
+
```
|
15
|
+
|
16
|
+
## Usage
|
17
|
+
Before using the gem create an integration and generate a secret token. Check [notion getting started guide](https://developers.notion.com/docs/getting-started) to learn more.
|
18
|
+
|
19
|
+
Pass the page id and secret token to the constructor and execute the `convert` method.
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
require 'notion_to_md'
|
23
|
+
|
24
|
+
notion_converter = NotionToMd::Converter.new(page_id: 'b91d5...', token: 'secret_...')
|
25
|
+
md = notion_converter.convert
|
26
|
+
```
|
27
|
+
|
28
|
+
If the secret token is provided as an environment variable —`NOTION_TOKEN`—, there's no need to pass it as an argument to the constructor.
|
29
|
+
|
30
|
+
```bash
|
31
|
+
$ export NOTION_TOKEN=<secret_...>
|
32
|
+
```
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
require 'notion_to_md'
|
36
|
+
|
37
|
+
notion_converter = NotionToMd::Converter.new(page_id: 'b91d5...')
|
38
|
+
md = notion_converter.convert
|
39
|
+
```
|
40
|
+
|
41
|
+
And that's all. The `md` is a string variable containing the notion page formatted in markdown.
|
42
|
+
|
43
|
+
## Test
|
44
|
+
```bash
|
45
|
+
$ ruby -Ilib:test test/notion_to_md/converter_spec.rb
|
46
|
+
```
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NotionToMd
|
4
|
+
class Block
|
5
|
+
class << self
|
6
|
+
def paragraph(block)
|
7
|
+
convert_text(block)
|
8
|
+
end
|
9
|
+
|
10
|
+
def heading_1(block)
|
11
|
+
"# #{convert_text(block)}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def heading_2(block)
|
15
|
+
"## #{convert_text(block)}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def heading_3(block)
|
19
|
+
"### #{convert_text(block)}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def callout(block)
|
23
|
+
icon = get_icon(block[:icon])
|
24
|
+
text = convert_text(block)
|
25
|
+
"#{icon} #{text}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def quote(block)
|
29
|
+
"> #{convert_text(block)}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def bulleted_list_item(block)
|
33
|
+
"- #{convert_text(block)}"
|
34
|
+
end
|
35
|
+
|
36
|
+
# TODO: numbered_list_item
|
37
|
+
def numbered_list_item(block)
|
38
|
+
Logger.info('numbered_list_item type not supported. Shown as bulleted_list_item.')
|
39
|
+
bulleted_list_item(block)
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_do(block)
|
43
|
+
checked = block[:checked]
|
44
|
+
text = convert_text(block)
|
45
|
+
|
46
|
+
"- #{checked ? '[x]' : '[ ]'} #{text}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def code(block)
|
50
|
+
language = block[:language]
|
51
|
+
text = convert_text(block)
|
52
|
+
|
53
|
+
"```#{language}\n\t#{text}\n```"
|
54
|
+
end
|
55
|
+
|
56
|
+
def embed(block)
|
57
|
+
url = block[:url]
|
58
|
+
|
59
|
+
"[#{url}](#{url})"
|
60
|
+
end
|
61
|
+
|
62
|
+
def image(block)
|
63
|
+
type = block[:type].to_sym
|
64
|
+
url = block.dig(type, :url)
|
65
|
+
caption = convert_caption(block)
|
66
|
+
|
67
|
+
"\n\n#{caption}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def bookmark(block)
|
71
|
+
url = block[:url]
|
72
|
+
"[#{url}](#{url})"
|
73
|
+
end
|
74
|
+
|
75
|
+
def divider(_block)
|
76
|
+
'---'
|
77
|
+
end
|
78
|
+
|
79
|
+
def blank
|
80
|
+
'<br />'
|
81
|
+
end
|
82
|
+
|
83
|
+
def convert_text(block)
|
84
|
+
block[:text].map do |text|
|
85
|
+
content = Text.send(text[:type], text)
|
86
|
+
enrich_text_content(text, content)
|
87
|
+
end.join
|
88
|
+
end
|
89
|
+
|
90
|
+
def convert_caption(block)
|
91
|
+
convert_text(text: block[:caption])
|
92
|
+
end
|
93
|
+
|
94
|
+
def get_icon(block)
|
95
|
+
type = block[:type].to_sym
|
96
|
+
block[type]
|
97
|
+
end
|
98
|
+
|
99
|
+
def enrich_text_content(text, content)
|
100
|
+
enriched_content = add_link(text, content)
|
101
|
+
add_annotations(text, enriched_content)
|
102
|
+
end
|
103
|
+
|
104
|
+
def add_link(text, content)
|
105
|
+
href = text[:href]
|
106
|
+
return content if href.nil?
|
107
|
+
|
108
|
+
"[#{content}](#{href})"
|
109
|
+
end
|
110
|
+
|
111
|
+
def add_annotations(text, content)
|
112
|
+
annotations = text[:annotations].select { |_key, value| !!value }
|
113
|
+
annotations.keys.inject(content) do |enriched_content, annotation|
|
114
|
+
TextAnnotation.send(annotation.to_sym, enriched_content)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -1,9 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'notion'
|
4
|
-
require_relative './logger'
|
5
|
-
require_relative './text_annotation'
|
6
|
-
|
7
3
|
module NotionToMd
|
8
4
|
class Converter
|
9
5
|
attr_reader :page_id
|
@@ -15,13 +11,19 @@ module NotionToMd
|
|
15
11
|
|
16
12
|
def convert
|
17
13
|
md = page_blocks[:results].map do |block|
|
18
|
-
next blank if block[:type] == 'paragraph' && block.dig(:paragraph, :text).empty?
|
14
|
+
next Block.blank if block[:type] == 'paragraph' && block.dig(:paragraph, :text).empty?
|
19
15
|
|
20
16
|
block_type = block[:type].to_sym
|
21
|
-
|
17
|
+
|
18
|
+
begin
|
19
|
+
Block.send(block_type, block[block_type])
|
20
|
+
rescue StandardError
|
21
|
+
Logger.info("Unsupported block type: #{block_type}")
|
22
|
+
next nil
|
23
|
+
end
|
22
24
|
end
|
23
25
|
Logger.info("Notion page #{page_id} converted to markdown")
|
24
|
-
md.join("\n\n")
|
26
|
+
md.compact.join("\n\n")
|
25
27
|
end
|
26
28
|
|
27
29
|
private
|
@@ -29,123 +31,5 @@ module NotionToMd
|
|
29
31
|
def page_blocks
|
30
32
|
@page_blocks ||= @notion.block_children(id: page_id)
|
31
33
|
end
|
32
|
-
|
33
|
-
|
34
|
-
def paragraph(block)
|
35
|
-
convert_text(block)
|
36
|
-
end
|
37
|
-
|
38
|
-
def heading_1(block)
|
39
|
-
"# #{convert_text(block)}"
|
40
|
-
end
|
41
|
-
|
42
|
-
def heading_2(block)
|
43
|
-
"## #{convert_text(block)}"
|
44
|
-
end
|
45
|
-
|
46
|
-
def heading_3(block)
|
47
|
-
"### #{convert_text(block)}"
|
48
|
-
end
|
49
|
-
|
50
|
-
def callout(block)
|
51
|
-
icon = get_icon(block[:icon])
|
52
|
-
text = convert_text(block)
|
53
|
-
"#{icon} #{text}"
|
54
|
-
end
|
55
|
-
|
56
|
-
def quote(block)
|
57
|
-
"> #{convert_text(block)}"
|
58
|
-
end
|
59
|
-
|
60
|
-
def bulleted_list_item(block)
|
61
|
-
"- #{convert_text(block)}"
|
62
|
-
end
|
63
|
-
|
64
|
-
# TODO: numbered_list_item
|
65
|
-
def numbered_list_item(block)
|
66
|
-
Logger.info('numbered_list_item type not supported. Shown as bulleted_list_item.')
|
67
|
-
bulleted_list_item(block)
|
68
|
-
end
|
69
|
-
|
70
|
-
def to_do(block)
|
71
|
-
checked = block[:checked]
|
72
|
-
text = convert_text(block)
|
73
|
-
|
74
|
-
"- #{checked ? '[x]' : '[ ]'} #{text}"
|
75
|
-
end
|
76
|
-
|
77
|
-
def code(block)
|
78
|
-
language = block[:language]
|
79
|
-
text = convert_text(block)
|
80
|
-
|
81
|
-
"```#{language}\n\t#{text}\n```"
|
82
|
-
end
|
83
|
-
|
84
|
-
def embed(block)
|
85
|
-
url = block[:url]
|
86
|
-
|
87
|
-
"[#{url}](#{url})"
|
88
|
-
end
|
89
|
-
|
90
|
-
def image(block)
|
91
|
-
type = block[:type].to_sym
|
92
|
-
url = block.dig(type, :url)
|
93
|
-
caption = convert_caption(block)
|
94
|
-
|
95
|
-
"\n\n#{caption}"
|
96
|
-
end
|
97
|
-
|
98
|
-
def bookmark(block)
|
99
|
-
url = block[:url]
|
100
|
-
"[#{url}](#{url})"
|
101
|
-
end
|
102
|
-
|
103
|
-
def divider(_block)
|
104
|
-
'---'
|
105
|
-
end
|
106
|
-
|
107
|
-
def equation(block)
|
108
|
-
equ = convert_text(block)
|
109
|
-
"$$ #{equ} $$"
|
110
|
-
end
|
111
|
-
|
112
|
-
def blank
|
113
|
-
'<br />'
|
114
|
-
end
|
115
|
-
|
116
|
-
def convert_text(block)
|
117
|
-
block[:text].map do |text|
|
118
|
-
content = text[:plain_text]
|
119
|
-
enrich_text_content(text, content)
|
120
|
-
end.join
|
121
|
-
end
|
122
|
-
|
123
|
-
def convert_caption(block)
|
124
|
-
convert_text(text: block[:caption])
|
125
|
-
end
|
126
|
-
|
127
|
-
def get_icon(block)
|
128
|
-
type = block[:type].to_sym
|
129
|
-
block[type]
|
130
|
-
end
|
131
|
-
|
132
|
-
def enrich_text_content(text, content)
|
133
|
-
enriched_content = add_link(text, content)
|
134
|
-
add_annotations(text, enriched_content)
|
135
|
-
end
|
136
|
-
|
137
|
-
def add_link(text, content)
|
138
|
-
href = text[:href]
|
139
|
-
return content if href.nil?
|
140
|
-
|
141
|
-
"[#{content}](#{href})"
|
142
|
-
end
|
143
|
-
|
144
|
-
def add_annotations(text, content)
|
145
|
-
annotations = text[:annotations].select { |key, value| !!value }
|
146
|
-
annotations.keys.inject(content) do |enriched_content, annotation|
|
147
|
-
TextAnnotation.send(annotation.to_sym, enriched_content)
|
148
|
-
end
|
149
|
-
end
|
150
34
|
end
|
151
35
|
end
|
data/lib/notion_to_md/logger.rb
CHANGED
@@ -1,16 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'logger'
|
4
|
-
|
5
3
|
module NotionToMd
|
6
4
|
class Logger
|
7
|
-
@logger = ::Logger.new(
|
5
|
+
@logger = ::Logger.new($stdout)
|
8
6
|
|
9
7
|
class << self
|
10
8
|
extend Forwardable
|
11
|
-
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
|
9
|
+
def_delegators :@logger, :debug, :info, :warn, :error, :fatal, :level, :level=
|
12
10
|
end
|
13
11
|
end
|
14
12
|
end
|
15
|
-
|
16
|
-
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module NotionToMd
|
2
4
|
# Append the text type:
|
3
5
|
# * italic: boolean,
|
@@ -9,19 +11,19 @@ module NotionToMd
|
|
9
11
|
class TextAnnotation
|
10
12
|
class << self
|
11
13
|
def italic(text)
|
12
|
-
"
|
14
|
+
"*#{text}*"
|
13
15
|
end
|
14
16
|
|
15
17
|
def bold(text)
|
16
18
|
"**#{text}**"
|
17
19
|
end
|
18
20
|
|
19
|
-
def
|
21
|
+
def strikethrough(text)
|
20
22
|
"~~#{text}~~"
|
21
23
|
end
|
22
24
|
|
23
25
|
def underline(text)
|
24
|
-
text
|
26
|
+
"<u>#{text}</u>"
|
25
27
|
end
|
26
28
|
|
27
29
|
def code(text)
|
data/lib/notion_to_md/version.rb
CHANGED
data/lib/notion_to_md.rb
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'notion'
|
4
|
+
require 'logger'
|
3
5
|
require_relative './notion_to_md/version'
|
4
6
|
require_relative './notion_to_md/converter'
|
7
|
+
require_relative './notion_to_md/logger'
|
8
|
+
require_relative './notion_to_md/block'
|
9
|
+
require_relative './notion_to_md/text'
|
10
|
+
require_relative './notion_to_md/text_annotation'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: notion_to_md
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Enrique Arias
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-02-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: notion-ruby-client
|
@@ -24,6 +24,48 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.0.8
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: hashie
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
27
69
|
description: Notion Markdown Exporter in Ruby
|
28
70
|
email: emoriarty81@gmail.com
|
29
71
|
executables: []
|
@@ -32,8 +74,10 @@ extra_rdoc_files: []
|
|
32
74
|
files:
|
33
75
|
- README.md
|
34
76
|
- lib/notion_to_md.rb
|
77
|
+
- lib/notion_to_md/block.rb
|
35
78
|
- lib/notion_to_md/converter.rb
|
36
79
|
- lib/notion_to_md/logger.rb
|
80
|
+
- lib/notion_to_md/text.rb
|
37
81
|
- lib/notion_to_md/text_annotation.rb
|
38
82
|
- lib/notion_to_md/version.rb
|
39
83
|
homepage: https://github.com/emoriarty/notion_to_md
|
@@ -48,7 +92,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
48
92
|
requirements:
|
49
93
|
- - ">="
|
50
94
|
- !ruby/object:Gem::Version
|
51
|
-
version:
|
95
|
+
version: '0'
|
52
96
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
97
|
requirements:
|
54
98
|
- - ">="
|