notion_to_md 2.4.1 → 2.5.1
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 +22 -5
- data/lib/notion_to_md/blocks/block.rb +4 -1
- data/lib/notion_to_md/blocks/builder.rb +4 -1
- data/lib/notion_to_md/blocks/bulleted_list_block.rb +1 -1
- data/lib/notion_to_md/blocks/bulleted_list_item_block.rb +1 -1
- data/lib/notion_to_md/blocks/factory.rb +6 -1
- data/lib/notion_to_md/blocks/normalizer.rb +18 -5
- data/lib/notion_to_md/blocks/numbered_list_block.rb +1 -1
- data/lib/notion_to_md/blocks/numbered_list_item_block.rb +1 -1
- data/lib/notion_to_md/blocks/table_block.rb +1 -1
- data/lib/notion_to_md/blocks/table_row_block.rb +1 -1
- data/lib/notion_to_md/blocks/to_do_list_block.rb +1 -1
- data/lib/notion_to_md/blocks/to_do_list_item_block.rb +1 -1
- data/lib/notion_to_md/blocks/types.rb +27 -1
- data/lib/notion_to_md/blocks.rb +4 -1
- data/lib/notion_to_md/converter.rb +14 -5
- data/lib/notion_to_md/helpers/yaml_sanitizer.rb +3 -1
- data/lib/notion_to_md/helpers.rb +2 -0
- data/lib/notion_to_md/logger.rb +1 -1
- data/lib/notion_to_md/page.rb +31 -10
- data/lib/notion_to_md/page_property.rb +2 -2
- data/lib/notion_to_md/text.rb +4 -2
- data/lib/notion_to_md/text_annotation.rb +1 -1
- data/lib/notion_to_md/version.rb +2 -2
- data/lib/notion_to_md.rb +21 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb8852f9013936bcb404e0779e4930e84831e2db4235b2f0bca8268a9e4edaf0
|
4
|
+
data.tar.gz: d3b9fe50d279cfc14abf20d7f8468d1534b043b73e00ee8123248556c03b43bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e49f3a1d040fb7381e8369c774cff8a31a510909c3e7813c4ba8016085075d613d01808a23a8075d9d9246335eadd1e08347225d287c702c07753df44f3f3af7
|
7
|
+
data.tar.gz: 52806a867c8d24e96e993c4a07741ff13322d14151e0285351c341237a772579f7084913764112f703435e963d598754e326e0c047c29f2d74f4ce6b58f68951
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# notion_to_md
|
2
2
|
Notion Markdown Exporter in Ruby.
|
3
3
|
|
4
|
+
The generated document is compliant with the [GitHub Flavored Markdown specification](https://github.github.com/gfm/).
|
5
|
+
|
4
6
|
## Installation
|
5
7
|
Use gem to install.
|
6
8
|
```bash
|
@@ -28,8 +30,6 @@ md = notion_converter.convert
|
|
28
30
|
Since v2.3 you can also use the convenient `convert` method from the root module.
|
29
31
|
|
30
32
|
```ruby
|
31
|
-
require 'notion_to_md'
|
32
|
-
|
33
33
|
md = NotionToMd.convert(page_id: 'b91d5...', token: 'secret_...')
|
34
34
|
```
|
35
35
|
|
@@ -40,15 +40,27 @@ $ export NOTION_TOKEN=<secret_...>
|
|
40
40
|
```
|
41
41
|
|
42
42
|
```ruby
|
43
|
-
require 'notion_to_md'
|
44
|
-
|
45
43
|
notion_converter = NotionToMd::Converter.new(page_id: 'b91d5...')
|
46
44
|
md = notion_converter.convert
|
47
45
|
# or
|
48
46
|
md = NotionToMd.convert(page_id: 'b91d5...')
|
49
47
|
```
|
50
48
|
|
51
|
-
And that's all. The `md` is a string variable containing the notion
|
49
|
+
And that's all. The `md` is a string variable containing the notion document formatted in markdown.
|
50
|
+
|
51
|
+
### Callable
|
52
|
+
|
53
|
+
From version 2.5.0, the `call` method is also available. It's an alias for `convert`.
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
md = NotionToMd.call(page_id: 'b91d5...')
|
57
|
+
```
|
58
|
+
|
59
|
+
The `call` method also supports the passing of a block.
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
NotionToMd.call(page_id: 'b91d5...') { puts _1 }
|
63
|
+
```
|
52
64
|
|
53
65
|
## Blocks
|
54
66
|
|
@@ -69,6 +81,11 @@ Everything in a notion page body is a [block object](https://developers.notion.c
|
|
69
81
|
* `table`
|
70
82
|
* `embed`
|
71
83
|
* `code`
|
84
|
+
* `link_preview`
|
85
|
+
* `file`
|
86
|
+
* `pdf`
|
87
|
+
* `video`
|
88
|
+
* `equation`
|
72
89
|
|
73
90
|
### Nested blocks
|
74
91
|
|
@@ -1,7 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
class NotionToMd
|
4
4
|
module Blocks
|
5
|
+
# === NotionToMd::Blocks::Builder
|
6
|
+
#
|
7
|
+
# This class is responsible for building a tree of blocks from the Notion API.
|
5
8
|
class Builder
|
6
9
|
##
|
7
10
|
# Array containing the block types allowed to have nested blocks (children).
|
@@ -1,8 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
class NotionToMd
|
4
4
|
module Blocks
|
5
|
+
# === NotionToMd::Blocks::Factory
|
6
|
+
#
|
7
|
+
# Factory class to create block instances based on the block type
|
5
8
|
class Factory
|
9
|
+
# rubocop:disable Metrics/MethodLength
|
6
10
|
def self.build(block:, children: [])
|
7
11
|
case block.type.to_sym
|
8
12
|
when :table
|
@@ -19,6 +23,7 @@ module NotionToMd
|
|
19
23
|
Blocks::Block.new(block: block, children: children)
|
20
24
|
end
|
21
25
|
end
|
26
|
+
# rubocop:enable Metrics/MethodLength
|
22
27
|
end
|
23
28
|
end
|
24
29
|
end
|
@@ -1,7 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
class NotionToMd
|
4
4
|
module Blocks
|
5
|
+
# === NotionToMd::Blocks::Normalizer
|
6
|
+
#
|
7
|
+
# This class is responsible for normalizing blocks of the same type
|
5
8
|
class Normalizer
|
6
9
|
# === Parameters
|
7
10
|
# blocks::
|
@@ -27,27 +30,37 @@ module NotionToMd
|
|
27
30
|
new_blocks = []
|
28
31
|
|
29
32
|
normalized_blocks.each do |block|
|
30
|
-
if block
|
33
|
+
if block_of_type?(block, type)
|
31
34
|
blocks_to_normalize << block
|
32
35
|
else
|
33
36
|
# When we encounter a block that is not of the provided type,
|
34
37
|
# we need to normalize the blocks we've collected so far.
|
35
38
|
# Then we add the current block to the new blocks array.
|
36
|
-
# This is
|
37
|
-
new_blocks
|
39
|
+
# This is to keep the order of the blocks as they are in the original array.
|
40
|
+
flush_blocks_to_normalize_into(new_blocks, type)
|
38
41
|
new_blocks << block
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
42
45
|
# If the last block is the provided type, it won't be added to the new blocks array.
|
43
46
|
# So, we need to normalize the blocks we've collected so far.
|
44
|
-
new_blocks
|
47
|
+
flush_blocks_to_normalize_into(new_blocks, type)
|
45
48
|
|
46
49
|
normalized_blocks.replace(new_blocks)
|
47
50
|
end
|
48
51
|
|
49
52
|
private
|
50
53
|
|
54
|
+
def block_of_type?(block, type)
|
55
|
+
block.type.to_sym == type
|
56
|
+
end
|
57
|
+
|
58
|
+
def flush_blocks_to_normalize_into(new_blocks, type)
|
59
|
+
return if blocks_to_normalize.empty?
|
60
|
+
|
61
|
+
new_blocks << new_block_and_reset_blocks_to_normalize(type)
|
62
|
+
end
|
63
|
+
|
51
64
|
def new_block_and_reset_blocks_to_normalize(type)
|
52
65
|
new_block = new_block_for(type, blocks_to_normalize)
|
53
66
|
@blocks_to_normalize = []
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
class NotionToMd
|
4
4
|
module Blocks
|
5
5
|
class Types
|
6
6
|
class << self
|
@@ -89,6 +89,32 @@ module NotionToMd
|
|
89
89
|
"|#{block[:cells].map(&method(:convert_table_row)).join('|')}|"
|
90
90
|
end
|
91
91
|
|
92
|
+
def link_preview(block)
|
93
|
+
url = block[:url]
|
94
|
+
|
95
|
+
"[#{url}](#{url})"
|
96
|
+
end
|
97
|
+
|
98
|
+
def file(block)
|
99
|
+
type = block[:type].to_sym
|
100
|
+
url = block.dig(type, :url)
|
101
|
+
caption = convert_caption(block)
|
102
|
+
|
103
|
+
"[#{url}](#{url})\n\n#{caption}"
|
104
|
+
end
|
105
|
+
|
106
|
+
def pdf(block)
|
107
|
+
file(block)
|
108
|
+
end
|
109
|
+
|
110
|
+
def video(block)
|
111
|
+
file(block)
|
112
|
+
end
|
113
|
+
|
114
|
+
def equation(block)
|
115
|
+
"$$#{block['expression']}$$"
|
116
|
+
end
|
117
|
+
|
92
118
|
private
|
93
119
|
|
94
120
|
def convert_table_row(cells)
|
data/lib/notion_to_md/blocks.rb
CHANGED
@@ -14,7 +14,10 @@ require_relative './blocks/numbered_list_item_block'
|
|
14
14
|
require_relative './blocks/to_do_list_block'
|
15
15
|
require_relative './blocks/to_do_list_item_block'
|
16
16
|
|
17
|
-
|
17
|
+
class NotionToMd
|
18
|
+
# === NotionToMd::Blocks
|
19
|
+
#
|
20
|
+
# This module is responsible for building Notion blocks.
|
18
21
|
module Blocks
|
19
22
|
# === Parameters
|
20
23
|
# block_id::
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
##
|
3
|
+
class NotionToMd
|
5
4
|
# The Converter class allows to transform notion pages to markdown documents.
|
6
5
|
# Just create a new Converter instance by providing the page_id:
|
7
6
|
# page_converter = NotionToMd::Converter.new(page_id: '9dc17c9c9d2e469dbbf0f9648f3288d3')
|
8
7
|
# Then, call for convert to obtain the markdown document:
|
9
8
|
# page_converter.convert
|
10
|
-
|
11
9
|
class Converter
|
12
|
-
|
10
|
+
include Callee
|
11
|
+
|
12
|
+
attr_reader :page_id, :frontmatter
|
13
13
|
|
14
14
|
# === Parameters
|
15
15
|
# page_id::
|
@@ -20,9 +20,10 @@ module NotionToMd
|
|
20
20
|
# === Returns
|
21
21
|
# A NotionToMd::Converter object.
|
22
22
|
#
|
23
|
-
def initialize(page_id:, token: nil)
|
23
|
+
def initialize(page_id:, token: nil, frontmatter: false)
|
24
24
|
@notion = Notion::Client.new(token: token || ENV['NOTION_TOKEN'])
|
25
25
|
@page_id = page_id
|
26
|
+
@frontmatter = frontmatter
|
26
27
|
end
|
27
28
|
|
28
29
|
# === Parameters
|
@@ -40,6 +41,14 @@ module NotionToMd
|
|
40
41
|
MD
|
41
42
|
end
|
42
43
|
|
44
|
+
def call
|
45
|
+
md = convert frontmatter: frontmatter
|
46
|
+
|
47
|
+
yield md if block_given?
|
48
|
+
|
49
|
+
md
|
50
|
+
end
|
51
|
+
|
43
52
|
private
|
44
53
|
|
45
54
|
def page
|
data/lib/notion_to_md/helpers.rb
CHANGED
data/lib/notion_to_md/logger.rb
CHANGED
data/lib/notion_to_md/page.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
class NotionToMd
|
4
|
+
# === NotionToMd::Page
|
5
|
+
#
|
6
|
+
# This class is responsible for representing a Notion page.
|
4
7
|
class Page
|
5
8
|
include Helpers::YamlSanitizer
|
6
9
|
|
@@ -81,17 +84,10 @@ module NotionToMd
|
|
81
84
|
end
|
82
85
|
|
83
86
|
def custom_props
|
84
|
-
@custom_props ||=
|
85
|
-
name = prop.first
|
86
|
-
value = prop.last # Notion::Messages::Message
|
87
|
-
type = value.type
|
88
|
-
|
89
|
-
next memo unless CustomProperty.respond_to?(type.to_sym)
|
90
|
-
|
91
|
-
memo[name.parameterize.underscore] = CustomProperty.send(type, value)
|
92
|
-
end.reject { |_k, v| v.presence.nil? }
|
87
|
+
@custom_props ||= filtered_custom_properties
|
93
88
|
end
|
94
89
|
|
90
|
+
# rubocop:disable Metrics/MethodLength
|
95
91
|
def default_props
|
96
92
|
@default_props ||= {
|
97
93
|
'id' => id,
|
@@ -107,10 +103,35 @@ module NotionToMd
|
|
107
103
|
'last_edited_by_id' => last_edited_by_id
|
108
104
|
}
|
109
105
|
end
|
106
|
+
# rubocop:enable Metrics/MethodLength
|
110
107
|
|
111
108
|
# This class is kept for retro compatibility reasons.
|
112
109
|
# Use instead the PageProperty class.
|
113
110
|
class CustomProperty < PageProperty
|
114
111
|
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def filtered_custom_properties
|
116
|
+
build_custom_properties.reject { |_k, v| v.presence.nil? }
|
117
|
+
end
|
118
|
+
|
119
|
+
def build_custom_properties
|
120
|
+
page.properties.each_with_object({}) do |(name, value), memo|
|
121
|
+
type = value.type
|
122
|
+
next unless valid_custom_property_type?(type)
|
123
|
+
|
124
|
+
key = name.parameterize.underscore
|
125
|
+
memo[key] = build_custom_property(type, value)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def valid_custom_property_type?(type)
|
130
|
+
CustomProperty.respond_to?(type.to_sym)
|
131
|
+
end
|
132
|
+
|
133
|
+
def build_custom_property(type, value)
|
134
|
+
CustomProperty.send(type, value)
|
135
|
+
end
|
115
136
|
end
|
116
137
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
class NotionToMd
|
4
4
|
class PageProperty
|
5
5
|
class << self
|
6
6
|
include Helpers::YamlSanitizer
|
@@ -66,7 +66,7 @@ module NotionToMd
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def checkbox(prop)
|
69
|
-
prop[:checkbox]
|
69
|
+
prop[:checkbox]&.to_s
|
70
70
|
rescue NoMethodError
|
71
71
|
nil
|
72
72
|
end
|
data/lib/notion_to_md/text.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class NotionToMd
|
2
4
|
class Text
|
3
5
|
class << self
|
4
6
|
def text(text)
|
@@ -6,7 +8,7 @@ module NotionToMd
|
|
6
8
|
end
|
7
9
|
|
8
10
|
def equation(text)
|
9
|
-
"
|
11
|
+
"$`#{text[:plain_text]}`$"
|
10
12
|
end
|
11
13
|
end
|
12
14
|
end
|
data/lib/notion_to_md/version.rb
CHANGED
data/lib/notion_to_md.rb
CHANGED
@@ -4,6 +4,7 @@ require 'notion'
|
|
4
4
|
require 'logger'
|
5
5
|
require 'active_support/inflector'
|
6
6
|
require 'active_support/core_ext/object/blank'
|
7
|
+
require 'callee'
|
7
8
|
require_relative './notion_to_md/helpers'
|
8
9
|
require_relative './notion_to_md/version'
|
9
10
|
require_relative './notion_to_md/converter'
|
@@ -14,7 +15,18 @@ require_relative './notion_to_md/blocks'
|
|
14
15
|
require_relative './notion_to_md/text'
|
15
16
|
require_relative './notion_to_md/text_annotation'
|
16
17
|
|
17
|
-
|
18
|
+
# The NotionToMd class allows to transform notion pages to markdown documents.
|
19
|
+
class NotionToMd
|
20
|
+
include Callee
|
21
|
+
|
22
|
+
attr_reader :page_id, :token, :frontmatter
|
23
|
+
|
24
|
+
def initialize(page_id:, token: nil, frontmatter: false)
|
25
|
+
@page_id = page_id
|
26
|
+
@token = token || ENV['NOTION_TOKEN']
|
27
|
+
@frontmatter = frontmatter
|
28
|
+
end
|
29
|
+
|
18
30
|
# === Parameters
|
19
31
|
# page_id::
|
20
32
|
# A string representing the notion page id.
|
@@ -29,4 +41,12 @@ module NotionToMd
|
|
29
41
|
def self.convert(page_id:, token: nil, frontmatter: false)
|
30
42
|
Converter.new(page_id: page_id, token: token).convert(frontmatter: frontmatter)
|
31
43
|
end
|
44
|
+
|
45
|
+
def call
|
46
|
+
md = self.class.convert(page_id: page_id, token: token, frontmatter: frontmatter)
|
47
|
+
|
48
|
+
yield md if block_given?
|
49
|
+
|
50
|
+
md
|
51
|
+
end
|
32
52
|
end
|
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: 2.
|
4
|
+
version: 2.5.1
|
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: 2025-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: callee
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.3.6
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.3.6
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: notion-ruby-client
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|