notionary 0.2.27__py3-none-any.whl → 0.2.28__py3-none-any.whl
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.
- notionary/__init__.py +5 -20
- notionary/blocks/client.py +87 -215
- notionary/blocks/enums.py +167 -0
- notionary/blocks/rich_text/markdown_rich_text_converter.py +266 -0
- notionary/blocks/rich_text/models.py +164 -0
- notionary/blocks/rich_text/name_id_resolver/__init__.py +11 -0
- notionary/blocks/rich_text/name_id_resolver/database.py +31 -0
- notionary/blocks/rich_text/name_id_resolver/page.py +34 -0
- notionary/blocks/rich_text/name_id_resolver/person.py +37 -0
- notionary/blocks/rich_text/name_id_resolver/port.py +11 -0
- notionary/blocks/rich_text/rich_text_markdown_converter.py +132 -0
- notionary/blocks/rich_text/rich_text_patterns.py +39 -0
- notionary/blocks/schemas.py +746 -0
- notionary/comments/client.py +52 -187
- notionary/comments/factory.py +40 -0
- notionary/comments/models.py +5 -127
- notionary/comments/schemas.py +240 -0
- notionary/comments/service.py +34 -0
- notionary/data_source/http/client.py +11 -0
- notionary/data_source/http/data_source_instance_client.py +94 -0
- notionary/data_source/properties/models.py +406 -0
- notionary/data_source/query/builder.py +429 -0
- notionary/data_source/query/resolver.py +114 -0
- notionary/data_source/query/schema.py +304 -0
- notionary/data_source/query/validator.py +73 -0
- notionary/data_source/schemas.py +27 -0
- notionary/data_source/service.py +353 -0
- notionary/database/client.py +30 -135
- notionary/database/database_metadata_update_client.py +19 -0
- notionary/database/schemas.py +29 -0
- notionary/database/service.py +169 -0
- notionary/exceptions/__init__.py +33 -0
- notionary/exceptions/api.py +41 -0
- notionary/exceptions/base.py +2 -0
- notionary/exceptions/block_parsing.py +16 -0
- notionary/exceptions/data_source/__init__.py +6 -0
- notionary/exceptions/data_source/builder.py +182 -0
- notionary/exceptions/data_source/properties.py +34 -0
- notionary/exceptions/properties.py +58 -0
- notionary/exceptions/search.py +33 -0
- notionary/file_upload/client.py +18 -30
- notionary/file_upload/models.py +7 -8
- notionary/file_upload/{notion_file_upload.py → service.py} +29 -64
- notionary/http/client.py +205 -0
- notionary/http/models.py +49 -0
- notionary/page/blocks/client.py +1 -0
- notionary/page/content/factory.py +68 -0
- notionary/page/content/markdown/__init__.py +5 -0
- notionary/page/content/markdown/builder.py +304 -0
- notionary/page/content/markdown/nodes/__init__.py +54 -0
- notionary/page/content/markdown/nodes/audio.py +23 -0
- notionary/page/content/markdown/nodes/base.py +12 -0
- notionary/page/content/markdown/nodes/bookmark.py +25 -0
- notionary/page/content/markdown/nodes/breadcrumb.py +14 -0
- notionary/page/content/markdown/nodes/bulleted_list.py +18 -0
- notionary/page/content/markdown/nodes/callout.py +32 -0
- notionary/page/content/markdown/nodes/code.py +30 -0
- notionary/page/content/markdown/nodes/columns.py +51 -0
- notionary/page/content/markdown/nodes/divider.py +14 -0
- notionary/page/content/markdown/nodes/embed.py +23 -0
- notionary/page/content/markdown/nodes/equation.py +19 -0
- notionary/page/content/markdown/nodes/file.py +23 -0
- notionary/page/content/markdown/nodes/heading.py +16 -0
- notionary/page/content/markdown/nodes/image.py +23 -0
- notionary/page/content/markdown/nodes/mixins/caption.py +12 -0
- notionary/page/content/markdown/nodes/numbered_list.py +15 -0
- notionary/page/content/markdown/nodes/paragraph.py +14 -0
- notionary/page/content/markdown/nodes/pdf.py +23 -0
- notionary/page/content/markdown/nodes/quote.py +15 -0
- notionary/page/content/markdown/nodes/space.py +14 -0
- notionary/page/content/markdown/nodes/table.py +45 -0
- notionary/page/content/markdown/nodes/table_of_contents.py +14 -0
- notionary/page/content/markdown/nodes/todo.py +22 -0
- notionary/page/content/markdown/nodes/toggle.py +28 -0
- notionary/page/content/markdown/nodes/toggleable_heading.py +35 -0
- notionary/page/content/markdown/nodes/video.py +23 -0
- notionary/page/content/parser/context.py +49 -0
- notionary/page/content/parser/factory.py +219 -0
- notionary/page/content/parser/parsers/__init__.py +60 -0
- notionary/page/content/parser/parsers/audio.py +40 -0
- notionary/page/content/parser/parsers/base.py +30 -0
- notionary/page/content/parser/parsers/bookmark.py +33 -0
- notionary/page/content/parser/parsers/breadcrumb.py +33 -0
- notionary/page/content/parser/parsers/bulleted_list.py +41 -0
- notionary/page/content/parser/parsers/callout.py +129 -0
- notionary/page/content/parser/parsers/caption.py +55 -0
- notionary/page/content/parser/parsers/code.py +81 -0
- notionary/page/content/parser/parsers/column.py +117 -0
- notionary/page/content/parser/parsers/column_list.py +81 -0
- notionary/page/content/parser/parsers/divider.py +33 -0
- notionary/page/content/parser/parsers/embed.py +33 -0
- notionary/page/content/parser/parsers/equation.py +65 -0
- notionary/page/content/parser/parsers/file.py +42 -0
- notionary/page/content/parser/parsers/heading.py +58 -0
- notionary/page/content/parser/parsers/image.py +42 -0
- notionary/page/content/parser/parsers/numbered_list.py +45 -0
- notionary/page/content/parser/parsers/paragraph.py +36 -0
- notionary/page/content/parser/parsers/pdf.py +42 -0
- notionary/page/content/parser/parsers/quote.py +65 -0
- notionary/page/content/parser/parsers/space.py +35 -0
- notionary/page/content/parser/parsers/table.py +144 -0
- notionary/page/content/parser/parsers/table_of_contents.py +32 -0
- notionary/page/content/parser/parsers/todo.py +58 -0
- notionary/page/content/parser/parsers/toggle.py +127 -0
- notionary/page/content/parser/parsers/toggleable_heading.py +150 -0
- notionary/page/content/parser/parsers/video.py +42 -0
- notionary/page/content/parser/post_processing/handlers/__init__.py +5 -0
- notionary/page/content/parser/post_processing/handlers/rich_text_length.py +93 -0
- notionary/page/content/parser/post_processing/handlers/rich_text_length_truncation.py +93 -0
- notionary/page/content/parser/post_processing/port.py +9 -0
- notionary/page/content/parser/post_processing/service.py +16 -0
- notionary/page/content/parser/pre_processsing/handlers/__init__.py +9 -0
- notionary/page/content/parser/pre_processsing/handlers/column_syntax.py +80 -0
- notionary/page/content/parser/pre_processsing/handlers/port.py +7 -0
- notionary/page/content/parser/pre_processsing/handlers/whitespace.py +68 -0
- notionary/page/content/parser/pre_processsing/service.py +15 -0
- notionary/page/content/parser/service.py +69 -0
- notionary/page/content/renderer/context.py +48 -0
- notionary/page/content/renderer/factory.py +240 -0
- notionary/page/content/renderer/post_processing/handlers/__init__.py +5 -0
- notionary/page/content/renderer/post_processing/handlers/numbered_list_placeholdere.py +62 -0
- notionary/page/content/renderer/post_processing/port.py +7 -0
- notionary/page/content/renderer/post_processing/service.py +15 -0
- notionary/page/content/renderer/renderers/__init__.py +57 -0
- notionary/page/content/renderer/renderers/audio.py +31 -0
- notionary/page/content/renderer/renderers/base.py +31 -0
- notionary/page/content/renderer/renderers/bookmark.py +25 -0
- notionary/page/content/renderer/renderers/breadcrumb.py +21 -0
- notionary/page/content/renderer/renderers/bulleted_list.py +48 -0
- notionary/page/content/renderer/renderers/callout.py +65 -0
- notionary/page/content/renderer/renderers/captioned_block.py +58 -0
- notionary/page/content/renderer/renderers/code.py +34 -0
- notionary/page/content/renderer/renderers/column.py +44 -0
- notionary/page/content/renderer/renderers/column_list.py +31 -0
- notionary/page/content/renderer/renderers/divider.py +22 -0
- notionary/page/content/renderer/renderers/embed.py +25 -0
- notionary/page/content/renderer/renderers/equation.py +37 -0
- notionary/page/content/renderer/renderers/fallback.py +24 -0
- notionary/page/content/renderer/renderers/file.py +40 -0
- notionary/page/content/renderer/renderers/heading.py +69 -0
- notionary/page/content/renderer/renderers/image.py +31 -0
- notionary/page/content/renderer/renderers/numbered_list.py +41 -0
- notionary/page/content/renderer/renderers/paragraph.py +40 -0
- notionary/page/content/renderer/renderers/pdf.py +31 -0
- notionary/page/content/renderer/renderers/quote.py +49 -0
- notionary/page/content/renderer/renderers/table.py +115 -0
- notionary/page/content/renderer/renderers/table_of_contents.py +26 -0
- notionary/page/content/renderer/renderers/table_row.py +17 -0
- notionary/page/content/renderer/renderers/todo.py +56 -0
- notionary/page/content/renderer/renderers/toggle.py +53 -0
- notionary/page/content/renderer/renderers/toggleable_heading.py +78 -0
- notionary/page/content/renderer/renderers/video.py +31 -0
- notionary/page/content/renderer/service.py +50 -0
- notionary/page/content/service.py +65 -0
- notionary/page/content/syntax/models.py +68 -0
- notionary/page/content/syntax/service.py +453 -0
- notionary/page/page_context.py +7 -16
- notionary/page/page_http_client.py +15 -0
- notionary/page/page_metadata_update_client.py +19 -0
- notionary/page/properties/client.py +144 -0
- notionary/page/properties/factory.py +26 -0
- notionary/page/properties/models.py +307 -0
- notionary/page/properties/service.py +257 -0
- notionary/page/schemas.py +13 -0
- notionary/page/service.py +222 -0
- notionary/shared/entity/client.py +29 -0
- notionary/shared/entity/dto_parsers.py +53 -0
- notionary/shared/entity/entity_metadata_update_client.py +41 -0
- notionary/shared/entity/schemas.py +45 -0
- notionary/shared/entity/service.py +171 -0
- notionary/shared/models/cover.py +20 -0
- notionary/shared/models/file.py +21 -0
- notionary/shared/models/icon.py +28 -0
- notionary/shared/models/parent.py +41 -0
- notionary/shared/properties/type.py +30 -0
- notionary/user/__init__.py +4 -8
- notionary/user/base.py +89 -0
- notionary/user/bot.py +70 -0
- notionary/user/client.py +22 -111
- notionary/user/person.py +41 -0
- notionary/user/schemas.py +67 -0
- notionary/user/service.py +65 -0
- notionary/utils/async_retry.py +39 -0
- notionary/utils/date.py +51 -0
- notionary/utils/fuzzy.py +56 -0
- notionary/{util/logging_mixin.py → utils/mixins/logging.py} +4 -16
- notionary/utils/pagination.py +50 -0
- notionary/utils/singleton.py +13 -0
- notionary/utils/uuid_utils.py +20 -0
- notionary/workspace/__init__.py +3 -0
- notionary/workspace/client.py +62 -0
- notionary/workspace/query/builder.py +60 -0
- notionary/workspace/query/models.py +60 -0
- notionary/workspace/query/service.py +93 -0
- notionary/workspace/schemas.py +21 -0
- notionary/workspace/service.py +116 -0
- {notionary-0.2.27.dist-info → notionary-0.2.28.dist-info}/METADATA +54 -49
- notionary-0.2.28.dist-info/RECORD +200 -0
- {notionary-0.2.27.dist-info → notionary-0.2.28.dist-info}/WHEEL +1 -1
- {notionary-0.2.27.dist-info → notionary-0.2.28.dist-info/licenses}/LICENSE +9 -9
- notionary/base_notion_client.py +0 -219
- notionary/blocks/__init__.py +0 -5
- notionary/blocks/_bootstrap.py +0 -271
- notionary/blocks/audio/__init__.py +0 -11
- notionary/blocks/audio/audio_element.py +0 -158
- notionary/blocks/audio/audio_markdown_node.py +0 -24
- notionary/blocks/audio/audio_models.py +0 -10
- notionary/blocks/base_block_element.py +0 -42
- notionary/blocks/bookmark/__init__.py +0 -12
- notionary/blocks/bookmark/bookmark_element.py +0 -83
- notionary/blocks/bookmark/bookmark_markdown_node.py +0 -28
- notionary/blocks/bookmark/bookmark_models.py +0 -15
- notionary/blocks/breadcrumbs/__init__.py +0 -15
- notionary/blocks/breadcrumbs/breadcrumb_element.py +0 -39
- notionary/blocks/breadcrumbs/breadcrumb_markdown_node.py +0 -13
- notionary/blocks/breadcrumbs/breadcrumb_models.py +0 -12
- notionary/blocks/bulleted_list/__init__.py +0 -15
- notionary/blocks/bulleted_list/bulleted_list_element.py +0 -74
- notionary/blocks/bulleted_list/bulleted_list_markdown_node.py +0 -20
- notionary/blocks/bulleted_list/bulleted_list_models.py +0 -17
- notionary/blocks/callout/__init__.py +0 -12
- notionary/blocks/callout/callout_element.py +0 -99
- notionary/blocks/callout/callout_markdown_node.py +0 -19
- notionary/blocks/callout/callout_models.py +0 -33
- notionary/blocks/child_database/__init__.py +0 -14
- notionary/blocks/child_database/child_database_element.py +0 -59
- notionary/blocks/child_database/child_database_models.py +0 -12
- notionary/blocks/child_page/__init__.py +0 -9
- notionary/blocks/child_page/child_page_element.py +0 -94
- notionary/blocks/child_page/child_page_models.py +0 -12
- notionary/blocks/code/__init__.py +0 -11
- notionary/blocks/code/code_element.py +0 -149
- notionary/blocks/code/code_markdown_node.py +0 -80
- notionary/blocks/code/code_models.py +0 -94
- notionary/blocks/column/__init__.py +0 -25
- notionary/blocks/column/column_element.py +0 -65
- notionary/blocks/column/column_list_element.py +0 -52
- notionary/blocks/column/column_list_markdown_node.py +0 -34
- notionary/blocks/column/column_markdown_node.py +0 -42
- notionary/blocks/column/column_models.py +0 -26
- notionary/blocks/divider/__init__.py +0 -12
- notionary/blocks/divider/divider_element.py +0 -41
- notionary/blocks/divider/divider_markdown_node.py +0 -11
- notionary/blocks/divider/divider_models.py +0 -12
- notionary/blocks/embed/__init__.py +0 -12
- notionary/blocks/embed/embed_element.py +0 -98
- notionary/blocks/embed/embed_markdown_node.py +0 -19
- notionary/blocks/embed/embed_models.py +0 -14
- notionary/blocks/equation/__init__.py +0 -13
- notionary/blocks/equation/equation_element.py +0 -133
- notionary/blocks/equation/equation_element_markdown_node.py +0 -23
- notionary/blocks/equation/equation_models.py +0 -11
- notionary/blocks/file/__init__.py +0 -23
- notionary/blocks/file/file_element.py +0 -133
- notionary/blocks/file/file_element_markdown_node.py +0 -24
- notionary/blocks/file/file_element_models.py +0 -39
- notionary/blocks/heading/__init__.py +0 -19
- notionary/blocks/heading/heading_element.py +0 -112
- notionary/blocks/heading/heading_markdown_node.py +0 -16
- notionary/blocks/heading/heading_models.py +0 -29
- notionary/blocks/image_block/__init__.py +0 -11
- notionary/blocks/image_block/image_element.py +0 -130
- notionary/blocks/image_block/image_markdown_node.py +0 -25
- notionary/blocks/image_block/image_models.py +0 -10
- notionary/blocks/markdown/markdown_builder.py +0 -525
- notionary/blocks/markdown/markdown_document_model.py +0 -0
- notionary/blocks/markdown/markdown_node.py +0 -25
- notionary/blocks/mixins/captions/__init__.py +0 -4
- notionary/blocks/mixins/captions/caption_markdown_node_mixin.py +0 -31
- notionary/blocks/mixins/captions/caption_mixin.py +0 -92
- notionary/blocks/mixins/file_upload/__init__.py +0 -3
- notionary/blocks/mixins/file_upload/file_upload_mixin.py +0 -320
- notionary/blocks/models.py +0 -174
- notionary/blocks/numbered_list/__init__.py +0 -16
- notionary/blocks/numbered_list/numbered_list_element.py +0 -65
- notionary/blocks/numbered_list/numbered_list_markdown_node.py +0 -17
- notionary/blocks/numbered_list/numbered_list_models.py +0 -17
- notionary/blocks/paragraph/__init__.py +0 -15
- notionary/blocks/paragraph/paragraph_element.py +0 -58
- notionary/blocks/paragraph/paragraph_markdown_node.py +0 -16
- notionary/blocks/paragraph/paragraph_models.py +0 -16
- notionary/blocks/pdf/__init__.py +0 -11
- notionary/blocks/pdf/pdf_element.py +0 -146
- notionary/blocks/pdf/pdf_markdown_node.py +0 -24
- notionary/blocks/pdf/pdf_models.py +0 -11
- notionary/blocks/quote/__init__.py +0 -14
- notionary/blocks/quote/quote_element.py +0 -75
- notionary/blocks/quote/quote_markdown_node.py +0 -16
- notionary/blocks/quote/quote_models.py +0 -18
- notionary/blocks/registry/__init__.py +0 -3
- notionary/blocks/registry/block_registry.py +0 -150
- notionary/blocks/rich_text/__init__.py +0 -33
- notionary/blocks/rich_text/rich_text_models.py +0 -221
- notionary/blocks/rich_text/text_inline_formatter.py +0 -456
- notionary/blocks/syntax_prompt_builder.py +0 -137
- notionary/blocks/table/__init__.py +0 -19
- notionary/blocks/table/table_element.py +0 -225
- notionary/blocks/table/table_markdown_node.py +0 -42
- notionary/blocks/table/table_models.py +0 -28
- notionary/blocks/table_of_contents/__init__.py +0 -17
- notionary/blocks/table_of_contents/table_of_contents_element.py +0 -80
- notionary/blocks/table_of_contents/table_of_contents_markdown_node.py +0 -21
- notionary/blocks/table_of_contents/table_of_contents_models.py +0 -18
- notionary/blocks/todo/__init__.py +0 -12
- notionary/blocks/todo/todo_element.py +0 -81
- notionary/blocks/todo/todo_markdown_node.py +0 -21
- notionary/blocks/todo/todo_models.py +0 -18
- notionary/blocks/toggle/__init__.py +0 -12
- notionary/blocks/toggle/toggle_element.py +0 -112
- notionary/blocks/toggle/toggle_markdown_node.py +0 -31
- notionary/blocks/toggle/toggle_models.py +0 -17
- notionary/blocks/toggleable_heading/__init__.py +0 -11
- notionary/blocks/toggleable_heading/toggleable_heading_element.py +0 -115
- notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +0 -34
- notionary/blocks/types.py +0 -130
- notionary/blocks/video/__init__.py +0 -11
- notionary/blocks/video/video_element.py +0 -187
- notionary/blocks/video/video_element_models.py +0 -10
- notionary/blocks/video/video_markdown_node.py +0 -26
- notionary/comments/__init__.py +0 -26
- notionary/database/__init__.py +0 -4
- notionary/database/database.py +0 -480
- notionary/database/database_filter_builder.py +0 -173
- notionary/database/database_provider.py +0 -227
- notionary/database/exceptions.py +0 -13
- notionary/database/factory.py +0 -0
- notionary/database/models.py +0 -337
- notionary/database/notion_database.py +0 -487
- notionary/file_upload/__init__.py +0 -7
- notionary/page/client.py +0 -124
- notionary/page/markdown_whitespace_processor.py +0 -129
- notionary/page/models.py +0 -322
- notionary/page/notion_page.py +0 -712
- notionary/page/page_content_deleting_service.py +0 -117
- notionary/page/page_content_writer.py +0 -80
- notionary/page/property_formatter.py +0 -99
- notionary/page/reader/handler/__init__.py +0 -19
- notionary/page/reader/handler/base_block_renderer.py +0 -44
- notionary/page/reader/handler/block_processing_context.py +0 -35
- notionary/page/reader/handler/block_rendering_context.py +0 -48
- notionary/page/reader/handler/column_list_renderer.py +0 -51
- notionary/page/reader/handler/column_renderer.py +0 -60
- notionary/page/reader/handler/equation_renderer.py +0 -0
- notionary/page/reader/handler/line_renderer.py +0 -73
- notionary/page/reader/handler/numbered_list_renderer.py +0 -85
- notionary/page/reader/handler/toggle_renderer.py +0 -69
- notionary/page/reader/handler/toggleable_heading_renderer.py +0 -89
- notionary/page/reader/page_content_retriever.py +0 -81
- notionary/page/search_filter_builder.py +0 -132
- notionary/page/utils.py +0 -60
- notionary/page/writer/handler/__init__.py +0 -24
- notionary/page/writer/handler/code_handler.py +0 -72
- notionary/page/writer/handler/column_handler.py +0 -141
- notionary/page/writer/handler/column_list_handler.py +0 -139
- notionary/page/writer/handler/equation_handler.py +0 -74
- notionary/page/writer/handler/line_handler.py +0 -35
- notionary/page/writer/handler/line_processing_context.py +0 -54
- notionary/page/writer/handler/regular_line_handler.py +0 -86
- notionary/page/writer/handler/table_handler.py +0 -66
- notionary/page/writer/handler/toggle_handler.py +0 -159
- notionary/page/writer/handler/toggleable_heading_handler.py +0 -174
- notionary/page/writer/markdown_to_notion_converter.py +0 -139
- notionary/page/writer/markdown_to_notion_converter_context.py +0 -30
- notionary/page/writer/markdown_to_notion_text_length_post_processor.py +0 -0
- notionary/page/writer/notion_text_length_processor.py +0 -150
- notionary/schemas/__init__.py +0 -3
- notionary/schemas/base.py +0 -73
- notionary/shared/__init__.py +0 -3
- notionary/shared/name_to_id_resolver.py +0 -203
- notionary/telemetry/__init__.py +0 -19
- notionary/telemetry/service.py +0 -136
- notionary/telemetry/views.py +0 -73
- notionary/user/base_notion_user.py +0 -53
- notionary/user/models.py +0 -84
- notionary/user/notion_bot_user.py +0 -226
- notionary/user/notion_user.py +0 -255
- notionary/user/notion_user_manager.py +0 -101
- notionary/util/__init__.py +0 -15
- notionary/util/concurrency_limiter.py +0 -0
- notionary/util/factory_decorator.py +0 -0
- notionary/util/factory_only.py +0 -37
- notionary/util/fuzzy.py +0 -75
- notionary/util/page_id_utils.py +0 -27
- notionary/util/singleton.py +0 -18
- notionary/util/singleton_metaclass.py +0 -22
- notionary/workspace.py +0 -105
- notionary-0.2.27.dist-info/RECORD +0 -202
@@ -0,0 +1,68 @@
|
|
1
|
+
from notionary.blocks.client import NotionBlockHttpClient
|
2
|
+
from notionary.page.content.parser.factory import ConverterChainFactory
|
3
|
+
from notionary.page.content.parser.post_processing.handlers import RichTextLengthTruncationPostProcessor
|
4
|
+
from notionary.page.content.parser.post_processing.service import BlockPostProcessor
|
5
|
+
from notionary.page.content.parser.pre_processsing.handlers import ColumnSyntaxPreProcessor, WhitespacePreProcessor
|
6
|
+
from notionary.page.content.parser.pre_processsing.service import MarkdownPreProcessor
|
7
|
+
from notionary.page.content.parser.service import MarkdownToNotionConverter
|
8
|
+
from notionary.page.content.renderer.factory import RendererChainFactory
|
9
|
+
from notionary.page.content.renderer.post_processing.handlers import NumberedListPlaceholderReplaceerPostProcessor
|
10
|
+
from notionary.page.content.renderer.post_processing.service import MarkdownRenderingPostProcessor
|
11
|
+
from notionary.page.content.renderer.service import NotionToMarkdownConverter
|
12
|
+
from notionary.page.content.service import PageContentService
|
13
|
+
|
14
|
+
|
15
|
+
class PageContentServiceFactory:
|
16
|
+
def __init__(
|
17
|
+
self,
|
18
|
+
converter_chain_factory: ConverterChainFactory | None = None,
|
19
|
+
renderer_chain_factory: RendererChainFactory | None = None,
|
20
|
+
) -> None:
|
21
|
+
self._converter_chain_factory = converter_chain_factory or ConverterChainFactory()
|
22
|
+
self._renderer_chain_factory = renderer_chain_factory or RendererChainFactory()
|
23
|
+
|
24
|
+
def create(self, page_id: str, block_client: NotionBlockHttpClient) -> PageContentService:
|
25
|
+
markdown_converter = self._create_markdown_to_notion_converter()
|
26
|
+
notion_to_markdown_converter = self._create_notion_to_markdown_converter()
|
27
|
+
|
28
|
+
return PageContentService(
|
29
|
+
page_id=page_id,
|
30
|
+
block_client=block_client,
|
31
|
+
markdown_converter=markdown_converter,
|
32
|
+
notion_to_markdown_converter=notion_to_markdown_converter,
|
33
|
+
)
|
34
|
+
|
35
|
+
def _create_markdown_to_notion_converter(self) -> MarkdownToNotionConverter:
|
36
|
+
line_parser = self._converter_chain_factory.create()
|
37
|
+
markdown_pre_processor = self._create_markdown_preprocessor()
|
38
|
+
block_post_processor = self._create_post_processor()
|
39
|
+
|
40
|
+
return MarkdownToNotionConverter(
|
41
|
+
line_parser=line_parser,
|
42
|
+
pre_processor=markdown_pre_processor,
|
43
|
+
post_processor=block_post_processor,
|
44
|
+
)
|
45
|
+
|
46
|
+
def _create_notion_to_markdown_converter(self) -> NotionToMarkdownConverter:
|
47
|
+
renderer_chain = self._renderer_chain_factory.create()
|
48
|
+
markdown_rendering_post_processor = self._create_markdown_rendering_post_processor()
|
49
|
+
return NotionToMarkdownConverter(
|
50
|
+
renderer_chain=renderer_chain,
|
51
|
+
post_processor=markdown_rendering_post_processor,
|
52
|
+
)
|
53
|
+
|
54
|
+
def _create_markdown_preprocessor(self) -> MarkdownPreProcessor:
|
55
|
+
pre_processor = MarkdownPreProcessor()
|
56
|
+
pre_processor.register(ColumnSyntaxPreProcessor())
|
57
|
+
pre_processor.register(WhitespacePreProcessor())
|
58
|
+
return pre_processor
|
59
|
+
|
60
|
+
def _create_post_processor(self) -> BlockPostProcessor:
|
61
|
+
post_processor = BlockPostProcessor()
|
62
|
+
post_processor.register(RichTextLengthTruncationPostProcessor())
|
63
|
+
return post_processor
|
64
|
+
|
65
|
+
def _create_markdown_rendering_post_processor(self) -> MarkdownRenderingPostProcessor:
|
66
|
+
post_processor = MarkdownRenderingPostProcessor()
|
67
|
+
post_processor.register(NumberedListPlaceholderReplaceerPostProcessor())
|
68
|
+
return post_processor
|
@@ -0,0 +1,304 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from collections.abc import Callable
|
4
|
+
from typing import Self
|
5
|
+
|
6
|
+
from notionary.blocks.enums import CodeLanguage
|
7
|
+
from notionary.page.content.markdown.nodes import (
|
8
|
+
AudioMarkdownNode,
|
9
|
+
BookmarkMarkdownNode,
|
10
|
+
BreadcrumbMarkdownNode,
|
11
|
+
BulletedListMarkdownNode,
|
12
|
+
CalloutMarkdownNode,
|
13
|
+
CodeMarkdownNode,
|
14
|
+
ColumnListMarkdownNode,
|
15
|
+
ColumnMarkdownNode,
|
16
|
+
DividerMarkdownNode,
|
17
|
+
EmbedMarkdownNode,
|
18
|
+
EquationMarkdownNode,
|
19
|
+
FileMarkdownNode,
|
20
|
+
HeadingMarkdownNode,
|
21
|
+
ImageMarkdownNode,
|
22
|
+
MarkdownNode,
|
23
|
+
NumberedListMarkdownNode,
|
24
|
+
ParagraphMarkdownNode,
|
25
|
+
PdfMarkdownNode,
|
26
|
+
QuoteMarkdownNode,
|
27
|
+
SpaceMarkdownNode,
|
28
|
+
TableMarkdownNode,
|
29
|
+
TableOfContentsMarkdownNode,
|
30
|
+
TodoMarkdownNode,
|
31
|
+
ToggleableHeadingMarkdownNode,
|
32
|
+
ToggleMarkdownNode,
|
33
|
+
VideoMarkdownNode,
|
34
|
+
)
|
35
|
+
|
36
|
+
|
37
|
+
class MarkdownBuilder:
|
38
|
+
def __init__(self) -> None:
|
39
|
+
self.children: list[MarkdownNode] = []
|
40
|
+
|
41
|
+
def h1(self, text: str) -> Self:
|
42
|
+
self.children.append(HeadingMarkdownNode(text=text, level=1))
|
43
|
+
return self
|
44
|
+
|
45
|
+
def h2(self, text: str) -> Self:
|
46
|
+
self.children.append(HeadingMarkdownNode(text=text, level=2))
|
47
|
+
return self
|
48
|
+
|
49
|
+
def h3(self, text: str) -> Self:
|
50
|
+
self.children.append(HeadingMarkdownNode(text=text, level=3))
|
51
|
+
return self
|
52
|
+
|
53
|
+
def paragraph(self, text: str) -> Self:
|
54
|
+
self.children.append(ParagraphMarkdownNode(text=text))
|
55
|
+
return self
|
56
|
+
|
57
|
+
def space(self) -> Self:
|
58
|
+
self.children.append(SpaceMarkdownNode())
|
59
|
+
return self
|
60
|
+
|
61
|
+
def quote(self, text: str) -> Self:
|
62
|
+
self.children.append(QuoteMarkdownNode(text=text))
|
63
|
+
return self
|
64
|
+
|
65
|
+
def divider(self) -> Self:
|
66
|
+
self.children.append(DividerMarkdownNode())
|
67
|
+
return self
|
68
|
+
|
69
|
+
def numbered_list(self, items: list[str]) -> Self:
|
70
|
+
self.children.append(NumberedListMarkdownNode(texts=items))
|
71
|
+
return self
|
72
|
+
|
73
|
+
def bulleted_list(self, items: list[str]) -> Self:
|
74
|
+
self.children.append(BulletedListMarkdownNode(texts=items))
|
75
|
+
return self
|
76
|
+
|
77
|
+
def todo(self, text: str, checked: bool = False) -> Self:
|
78
|
+
self.children.append(TodoMarkdownNode(text=text, checked=checked))
|
79
|
+
return self
|
80
|
+
|
81
|
+
def checked_todo(self, text: str) -> Self:
|
82
|
+
return self.todo(text, checked=True)
|
83
|
+
|
84
|
+
def unchecked_todo(self, text: str) -> Self:
|
85
|
+
return self.todo(text, checked=False)
|
86
|
+
|
87
|
+
def todo_list(self, items: list[str], completed: list[bool] | None = None) -> Self:
|
88
|
+
if completed is None:
|
89
|
+
completed = [False] * len(items)
|
90
|
+
|
91
|
+
for i, item in enumerate(items):
|
92
|
+
is_done = completed[i] if i < len(completed) else False
|
93
|
+
self.children.append(TodoMarkdownNode(text=item, checked=is_done))
|
94
|
+
return self
|
95
|
+
|
96
|
+
def callout(self, text: str, emoji: str | None = None) -> Self:
|
97
|
+
self.children.append(CalloutMarkdownNode(text=text, emoji=emoji))
|
98
|
+
return self
|
99
|
+
|
100
|
+
def callout_with_children(
|
101
|
+
self,
|
102
|
+
text: str,
|
103
|
+
emoji: str | None = None,
|
104
|
+
builder_func: Callable[[MarkdownBuilder], MarkdownBuilder] | None = None,
|
105
|
+
) -> Self:
|
106
|
+
"""
|
107
|
+
Add a callout block with children built using the builder API.
|
108
|
+
|
109
|
+
Args:
|
110
|
+
text: The callout text content
|
111
|
+
emoji: Optional emoji for the callout icon
|
112
|
+
builder_func: Optional function that receives a MarkdownBuilder and returns it configured
|
113
|
+
|
114
|
+
Example:
|
115
|
+
builder.callout_with_children("Important note", "⚠️", lambda c:
|
116
|
+
c.paragraph("Additional details here")
|
117
|
+
.bulleted_list(["Point 1", "Point 2"])
|
118
|
+
)
|
119
|
+
"""
|
120
|
+
if builder_func is None:
|
121
|
+
self.children.append(CalloutMarkdownNode(text=text, emoji=emoji))
|
122
|
+
return self
|
123
|
+
|
124
|
+
callout_builder = MarkdownBuilder()
|
125
|
+
builder_func(callout_builder)
|
126
|
+
self.children.append(CalloutMarkdownNode(text=text, emoji=emoji, children=callout_builder.children))
|
127
|
+
return self
|
128
|
+
|
129
|
+
def toggle(self, title: str, builder_func: Callable[[MarkdownBuilder], MarkdownBuilder]) -> Self:
|
130
|
+
"""
|
131
|
+
Add a toggle block with content built using the builder API.
|
132
|
+
|
133
|
+
Args:
|
134
|
+
title: The toggle title/header text
|
135
|
+
builder_func: Function that receives a MarkdownBuilder and returns it configured
|
136
|
+
|
137
|
+
Example:
|
138
|
+
builder.toggle("Advanced Settings", lambda t:
|
139
|
+
t.h3("Configuration")
|
140
|
+
.paragraph("Settings description")
|
141
|
+
.table(["Setting", "Value"], [["Debug", "True"]])
|
142
|
+
.callout("Important note", "⚠️")
|
143
|
+
)
|
144
|
+
"""
|
145
|
+
toggle_builder = MarkdownBuilder()
|
146
|
+
builder_func(toggle_builder)
|
147
|
+
self.children.append(ToggleMarkdownNode(title=title, children=toggle_builder.children))
|
148
|
+
return self
|
149
|
+
|
150
|
+
def toggleable_heading(
|
151
|
+
self,
|
152
|
+
text: str,
|
153
|
+
level: int,
|
154
|
+
builder_func: Callable[[MarkdownBuilder], MarkdownBuilder],
|
155
|
+
) -> Self:
|
156
|
+
"""
|
157
|
+
Add a toggleable heading with content built using the builder API.
|
158
|
+
|
159
|
+
Args:
|
160
|
+
text: The heading text content
|
161
|
+
level: Heading level (1-3)
|
162
|
+
builder_func: Function that receives a MarkdownBuilder and returns it configured
|
163
|
+
|
164
|
+
Example:
|
165
|
+
builder.toggleable_heading("Advanced Section", 2, lambda t:
|
166
|
+
t.paragraph("Introduction to this section")
|
167
|
+
.numbered_list(["Step 1", "Step 2", "Step 3"])
|
168
|
+
.code("example_code()", "python")
|
169
|
+
.table(["Feature", "Status"], [["API", "Ready"]])
|
170
|
+
)
|
171
|
+
"""
|
172
|
+
toggle_builder = MarkdownBuilder()
|
173
|
+
builder_func(toggle_builder)
|
174
|
+
self.children.append(ToggleableHeadingMarkdownNode(text=text, level=level, children=toggle_builder.children))
|
175
|
+
return self
|
176
|
+
|
177
|
+
def image(self, url: str, caption: str | None = None) -> Self:
|
178
|
+
self.children.append(ImageMarkdownNode(url=url, caption=caption))
|
179
|
+
return self
|
180
|
+
|
181
|
+
def video(self, url: str, caption: str | None = None) -> Self:
|
182
|
+
self.children.append(VideoMarkdownNode(url=url, caption=caption))
|
183
|
+
return self
|
184
|
+
|
185
|
+
def audio(self, url: str, caption: str | None = None) -> Self:
|
186
|
+
self.children.append(AudioMarkdownNode(url=url, caption=caption))
|
187
|
+
return self
|
188
|
+
|
189
|
+
def file(self, url: str, caption: str | None = None) -> Self:
|
190
|
+
self.children.append(FileMarkdownNode(url=url, caption=caption))
|
191
|
+
return self
|
192
|
+
|
193
|
+
def pdf(self, url: str, caption: str | None = None) -> Self:
|
194
|
+
self.children.append(PdfMarkdownNode(url=url, caption=caption))
|
195
|
+
return self
|
196
|
+
|
197
|
+
def bookmark(self, url: str, title: str | None = None, caption: str | None = None) -> Self:
|
198
|
+
self.children.append(BookmarkMarkdownNode(url=url, title=title, caption=caption))
|
199
|
+
return self
|
200
|
+
|
201
|
+
def embed(self, url: str, caption: str | None = None) -> Self:
|
202
|
+
self.children.append(EmbedMarkdownNode(url=url, caption=caption))
|
203
|
+
return self
|
204
|
+
|
205
|
+
def code(self, code: str, language: CodeLanguage | None = None, caption: str | None = None) -> Self:
|
206
|
+
self.children.append(CodeMarkdownNode(code=code, language=language, caption=caption))
|
207
|
+
return self
|
208
|
+
|
209
|
+
def mermaid(self, diagram: str, caption: str | None = None) -> Self:
|
210
|
+
self.children.append(CodeMarkdownNode(code=diagram, language=CodeLanguage.MERMAID.value, caption=caption))
|
211
|
+
return self
|
212
|
+
|
213
|
+
def table(self, headers: list[str], rows: list[list[str]]) -> Self:
|
214
|
+
self.children.append(TableMarkdownNode(headers=headers, rows=rows))
|
215
|
+
return self
|
216
|
+
|
217
|
+
def add_custom(self, node: MarkdownNode) -> Self:
|
218
|
+
self.children.append(node)
|
219
|
+
return self
|
220
|
+
|
221
|
+
def breadcrumb(self) -> Self:
|
222
|
+
self.children.append(BreadcrumbMarkdownNode())
|
223
|
+
return self
|
224
|
+
|
225
|
+
def equation(self, expression: str) -> Self:
|
226
|
+
self.children.append(EquationMarkdownNode(expression=expression))
|
227
|
+
return self
|
228
|
+
|
229
|
+
def table_of_contents(self) -> Self:
|
230
|
+
self.children.append(TableOfContentsMarkdownNode())
|
231
|
+
return self
|
232
|
+
|
233
|
+
def columns(
|
234
|
+
self,
|
235
|
+
*builder_funcs: Callable[[MarkdownBuilder], MarkdownBuilder],
|
236
|
+
width_ratios: list[float] | None = None,
|
237
|
+
) -> Self:
|
238
|
+
"""
|
239
|
+
Add multiple columns in a layout.
|
240
|
+
|
241
|
+
Args:
|
242
|
+
*builder_funcs: Multiple functions, each building one column
|
243
|
+
width_ratios: Optional list of width ratios (0.0 to 1.0).
|
244
|
+
If None, columns have equal width.
|
245
|
+
Length must match number of builder_funcs.
|
246
|
+
|
247
|
+
Examples:
|
248
|
+
# Equal width (original API unchanged):
|
249
|
+
builder.columns(
|
250
|
+
lambda col: col.h2("Left").paragraph("Left content"),
|
251
|
+
lambda col: col.h2("Right").paragraph("Right content")
|
252
|
+
)
|
253
|
+
|
254
|
+
# Custom ratios:
|
255
|
+
builder.columns(
|
256
|
+
lambda col: col.h2("Main").paragraph("70% width"),
|
257
|
+
lambda col: col.h2("Sidebar").paragraph("30% width"),
|
258
|
+
width_ratios=[0.7, 0.3]
|
259
|
+
)
|
260
|
+
|
261
|
+
# Three columns with custom ratios:
|
262
|
+
builder.columns(
|
263
|
+
lambda col: col.h3("Nav").paragraph("Navigation"),
|
264
|
+
lambda col: col.h2("Main").paragraph("Main content"),
|
265
|
+
lambda col: col.h3("Ads").paragraph("Advertisement"),
|
266
|
+
width_ratios=[0.2, 0.6, 0.2]
|
267
|
+
)
|
268
|
+
"""
|
269
|
+
self._validate_columns_args(builder_funcs, width_ratios)
|
270
|
+
|
271
|
+
# Create all columns
|
272
|
+
columns = []
|
273
|
+
for i, builder_func in enumerate(builder_funcs):
|
274
|
+
width_ratio = width_ratios[i] if width_ratios else None
|
275
|
+
|
276
|
+
col_builder = MarkdownBuilder()
|
277
|
+
builder_func(col_builder)
|
278
|
+
|
279
|
+
column_node = ColumnMarkdownNode(children=col_builder.children, width_ratio=width_ratio)
|
280
|
+
columns.append(column_node)
|
281
|
+
|
282
|
+
self.children.append(ColumnListMarkdownNode(columns=columns))
|
283
|
+
return self
|
284
|
+
|
285
|
+
def _validate_columns_args(
|
286
|
+
self,
|
287
|
+
builder_funcs: tuple[Callable[[MarkdownBuilder], MarkdownBuilder], ...],
|
288
|
+
width_ratios: list[float] | None,
|
289
|
+
) -> None:
|
290
|
+
if len(builder_funcs) < 2:
|
291
|
+
raise ValueError("Column layout requires at least 2 columns")
|
292
|
+
|
293
|
+
if width_ratios is not None:
|
294
|
+
if len(width_ratios) != len(builder_funcs):
|
295
|
+
raise ValueError(
|
296
|
+
f"width_ratios length ({len(width_ratios)}) must match number of columns ({len(builder_funcs)})"
|
297
|
+
)
|
298
|
+
|
299
|
+
ratio_sum = sum(width_ratios)
|
300
|
+
if not (0.9 <= ratio_sum <= 1.1): # Allow small floating point errors
|
301
|
+
raise ValueError(f"width_ratios should sum to 1.0, got {ratio_sum}")
|
302
|
+
|
303
|
+
def build(self) -> str:
|
304
|
+
return "\n\n".join(child.to_markdown() for child in self.children if child is not None)
|
@@ -0,0 +1,54 @@
|
|
1
|
+
from .audio import AudioMarkdownNode
|
2
|
+
from .base import MarkdownNode
|
3
|
+
from .bookmark import BookmarkMarkdownNode
|
4
|
+
from .breadcrumb import BreadcrumbMarkdownNode
|
5
|
+
from .bulleted_list import BulletedListMarkdownNode
|
6
|
+
from .callout import CalloutMarkdownNode
|
7
|
+
from .code import CodeMarkdownNode
|
8
|
+
from .columns import ColumnListMarkdownNode, ColumnMarkdownNode
|
9
|
+
from .divider import DividerMarkdownNode
|
10
|
+
from .embed import EmbedMarkdownNode
|
11
|
+
from .equation import EquationMarkdownNode
|
12
|
+
from .file import FileMarkdownNode
|
13
|
+
from .heading import HeadingMarkdownNode
|
14
|
+
from .image import ImageMarkdownNode
|
15
|
+
from .numbered_list import NumberedListMarkdownNode
|
16
|
+
from .paragraph import ParagraphMarkdownNode
|
17
|
+
from .pdf import PdfMarkdownNode
|
18
|
+
from .quote import QuoteMarkdownNode
|
19
|
+
from .space import SpaceMarkdownNode
|
20
|
+
from .table import TableMarkdownNode
|
21
|
+
from .table_of_contents import TableOfContentsMarkdownNode
|
22
|
+
from .todo import TodoMarkdownNode
|
23
|
+
from .toggle import ToggleMarkdownNode
|
24
|
+
from .toggleable_heading import ToggleableHeadingMarkdownNode
|
25
|
+
from .video import VideoMarkdownNode
|
26
|
+
|
27
|
+
__all__ = [
|
28
|
+
"AudioMarkdownNode",
|
29
|
+
"BookmarkMarkdownNode",
|
30
|
+
"BreadcrumbMarkdownNode",
|
31
|
+
"BulletedListMarkdownNode",
|
32
|
+
"CalloutMarkdownNode",
|
33
|
+
"CodeMarkdownNode",
|
34
|
+
"ColumnListMarkdownNode",
|
35
|
+
"ColumnMarkdownNode",
|
36
|
+
"DividerMarkdownNode",
|
37
|
+
"EmbedMarkdownNode",
|
38
|
+
"EquationMarkdownNode",
|
39
|
+
"FileMarkdownNode",
|
40
|
+
"HeadingMarkdownNode",
|
41
|
+
"ImageMarkdownNode",
|
42
|
+
"MarkdownNode",
|
43
|
+
"NumberedListMarkdownNode",
|
44
|
+
"ParagraphMarkdownNode",
|
45
|
+
"PdfMarkdownNode",
|
46
|
+
"QuoteMarkdownNode",
|
47
|
+
"SpaceMarkdownNode",
|
48
|
+
"TableMarkdownNode",
|
49
|
+
"TableOfContentsMarkdownNode",
|
50
|
+
"TodoMarkdownNode",
|
51
|
+
"ToggleMarkdownNode",
|
52
|
+
"ToggleableHeadingMarkdownNode",
|
53
|
+
"VideoMarkdownNode",
|
54
|
+
]
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from typing import override
|
2
|
+
|
3
|
+
from notionary.page.content.markdown.nodes.base import MarkdownNode
|
4
|
+
from notionary.page.content.markdown.nodes.mixins.caption import CaptionMarkdownNodeMixin
|
5
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
6
|
+
|
7
|
+
|
8
|
+
class AudioMarkdownNode(MarkdownNode, CaptionMarkdownNodeMixin):
|
9
|
+
def __init__(
|
10
|
+
self,
|
11
|
+
url: str,
|
12
|
+
caption: str | None = None,
|
13
|
+
syntax_registry: SyntaxRegistry | None = None,
|
14
|
+
) -> None:
|
15
|
+
super().__init__(syntax_registry=syntax_registry)
|
16
|
+
self.url = url
|
17
|
+
self.caption = caption
|
18
|
+
|
19
|
+
@override
|
20
|
+
def to_markdown(self) -> str:
|
21
|
+
audio_syntax = self._syntax_registry.get_audio_syntax()
|
22
|
+
base_markdown = f"{audio_syntax.start_delimiter}{self.url}{audio_syntax.end_delimiter}"
|
23
|
+
return self._append_caption_to_markdown(base_markdown, self.caption)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
|
3
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
4
|
+
|
5
|
+
|
6
|
+
class MarkdownNode(ABC):
|
7
|
+
def __init__(self, syntax_registry: SyntaxRegistry | None = None) -> None:
|
8
|
+
self._syntax_registry = syntax_registry or SyntaxRegistry()
|
9
|
+
|
10
|
+
@abstractmethod
|
11
|
+
def to_markdown(self) -> str:
|
12
|
+
pass
|
@@ -0,0 +1,25 @@
|
|
1
|
+
from typing import override
|
2
|
+
|
3
|
+
from notionary.page.content.markdown.nodes.base import MarkdownNode
|
4
|
+
from notionary.page.content.markdown.nodes.mixins.caption import CaptionMarkdownNodeMixin
|
5
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
6
|
+
|
7
|
+
|
8
|
+
class BookmarkMarkdownNode(MarkdownNode, CaptionMarkdownNodeMixin):
|
9
|
+
def __init__(
|
10
|
+
self,
|
11
|
+
url: str,
|
12
|
+
title: str | None = None,
|
13
|
+
caption: str | None = None,
|
14
|
+
syntax_registry: SyntaxRegistry | None = None,
|
15
|
+
) -> None:
|
16
|
+
super().__init__(syntax_registry=syntax_registry)
|
17
|
+
self.url = url
|
18
|
+
self.title = title
|
19
|
+
self.caption = caption
|
20
|
+
|
21
|
+
@override
|
22
|
+
def to_markdown(self) -> str:
|
23
|
+
bookmark_syntax = self._syntax_registry.get_bookmark_syntax()
|
24
|
+
base_markdown = f"{bookmark_syntax.start_delimiter}{self.url}{bookmark_syntax.end_delimiter}"
|
25
|
+
return self._append_caption_to_markdown(base_markdown, self.caption)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
from typing import override
|
2
|
+
|
3
|
+
from notionary.page.content.markdown.nodes.base import MarkdownNode
|
4
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
5
|
+
|
6
|
+
|
7
|
+
class BreadcrumbMarkdownNode(MarkdownNode):
|
8
|
+
def __init__(self, syntax_registry: SyntaxRegistry | None = None) -> None:
|
9
|
+
super().__init__(syntax_registry=syntax_registry)
|
10
|
+
|
11
|
+
@override
|
12
|
+
def to_markdown(self) -> str:
|
13
|
+
breadcrumb_syntax = self._syntax_registry.get_breadcrumb_syntax()
|
14
|
+
return breadcrumb_syntax.start_delimiter
|
@@ -0,0 +1,18 @@
|
|
1
|
+
from typing import override
|
2
|
+
|
3
|
+
from notionary.page.content.markdown.nodes.base import MarkdownNode
|
4
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
5
|
+
|
6
|
+
|
7
|
+
class BulletedListMarkdownNode(MarkdownNode):
|
8
|
+
def __init__(self, texts: list[str], syntax_registry: SyntaxRegistry | None = None) -> None:
|
9
|
+
super().__init__(syntax_registry=syntax_registry)
|
10
|
+
self.texts = texts
|
11
|
+
|
12
|
+
@override
|
13
|
+
def to_markdown(self) -> str:
|
14
|
+
bulleted_list_syntax = self._syntax_registry.get_bulleted_list_syntax()
|
15
|
+
result = []
|
16
|
+
for text in self.texts:
|
17
|
+
result.append(f"{bulleted_list_syntax.start_delimiter} {text}")
|
18
|
+
return "\n".join(result)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
from typing import override
|
2
|
+
|
3
|
+
from notionary.page.content.markdown.nodes.base import MarkdownNode
|
4
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
5
|
+
|
6
|
+
|
7
|
+
class CalloutMarkdownNode(MarkdownNode):
|
8
|
+
def __init__(
|
9
|
+
self,
|
10
|
+
text: str,
|
11
|
+
emoji: str | None = None,
|
12
|
+
children: list[MarkdownNode] | None = None,
|
13
|
+
syntax_registry: SyntaxRegistry | None = None,
|
14
|
+
):
|
15
|
+
super().__init__(syntax_registry=syntax_registry)
|
16
|
+
self.text = text
|
17
|
+
self.emoji = emoji
|
18
|
+
self.children = children or []
|
19
|
+
|
20
|
+
@override
|
21
|
+
def to_markdown(self) -> str:
|
22
|
+
callout_syntax = self._syntax_registry.get_callout_syntax()
|
23
|
+
start_tag = f"{callout_syntax.start_delimiter} {self.emoji}" if self.emoji else callout_syntax.start_delimiter
|
24
|
+
|
25
|
+
if not self.children:
|
26
|
+
return f"{start_tag}\n{self.text}\n{callout_syntax.end_delimiter}"
|
27
|
+
|
28
|
+
# Convert children to markdown
|
29
|
+
content_parts = [self.text] + [child.to_markdown() for child in self.children]
|
30
|
+
content_text = "\n\n".join(content_parts)
|
31
|
+
|
32
|
+
return f"{start_tag}\n{content_text}\n{callout_syntax.end_delimiter}"
|
@@ -0,0 +1,30 @@
|
|
1
|
+
from typing import override
|
2
|
+
|
3
|
+
from notionary.blocks.enums import CodeLanguage
|
4
|
+
from notionary.page.content.markdown.nodes.base import MarkdownNode
|
5
|
+
from notionary.page.content.markdown.nodes.mixins.caption import CaptionMarkdownNodeMixin
|
6
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
7
|
+
|
8
|
+
|
9
|
+
class CodeMarkdownNode(MarkdownNode, CaptionMarkdownNodeMixin):
|
10
|
+
"""Code node for creating Notion-style code blocks."""
|
11
|
+
|
12
|
+
def __init__(
|
13
|
+
self,
|
14
|
+
code: str,
|
15
|
+
language: CodeLanguage | None = None,
|
16
|
+
caption: str | None = None,
|
17
|
+
syntax_registry: SyntaxRegistry | None = None,
|
18
|
+
) -> None:
|
19
|
+
super().__init__(syntax_registry=syntax_registry)
|
20
|
+
self.code = code
|
21
|
+
self.language = language
|
22
|
+
self.caption = caption
|
23
|
+
|
24
|
+
@override
|
25
|
+
def to_markdown(self) -> str:
|
26
|
+
code_syntax = self._syntax_registry.get_code_syntax()
|
27
|
+
lang = self.language or ""
|
28
|
+
|
29
|
+
base_markdown = f"{code_syntax.start_delimiter}{lang}\n{self.code}\n{code_syntax.end_delimiter}"
|
30
|
+
return self._append_caption_to_markdown(base_markdown, self.caption)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
from typing import override
|
2
|
+
|
3
|
+
from notionary.page.content.markdown.nodes.base import MarkdownNode
|
4
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
5
|
+
|
6
|
+
|
7
|
+
class ColumnMarkdownNode(MarkdownNode):
|
8
|
+
def __init__(
|
9
|
+
self,
|
10
|
+
children: list[MarkdownNode] | None = None,
|
11
|
+
width_ratio: float | None = None,
|
12
|
+
syntax_registry: SyntaxRegistry | None = None,
|
13
|
+
):
|
14
|
+
super().__init__(syntax_registry=syntax_registry)
|
15
|
+
self.children = children or []
|
16
|
+
self.width_ratio = width_ratio
|
17
|
+
|
18
|
+
@override
|
19
|
+
def to_markdown(self) -> str:
|
20
|
+
column_syntax = self._syntax_registry.get_column_syntax()
|
21
|
+
start_tag = (
|
22
|
+
f"{column_syntax.start_delimiter} {self.width_ratio}"
|
23
|
+
if self.width_ratio is not None
|
24
|
+
else column_syntax.start_delimiter
|
25
|
+
)
|
26
|
+
|
27
|
+
if not self.children:
|
28
|
+
return f"{start_tag}\n{column_syntax.end_delimiter}"
|
29
|
+
|
30
|
+
# Convert children to markdown
|
31
|
+
content_parts = [child.to_markdown() for child in self.children]
|
32
|
+
content_text = "\n\n".join(content_parts)
|
33
|
+
|
34
|
+
return f"{start_tag}\n{content_text}\n{column_syntax.end_delimiter}"
|
35
|
+
|
36
|
+
|
37
|
+
class ColumnListMarkdownNode(MarkdownNode):
|
38
|
+
def __init__(self, columns: list[ColumnMarkdownNode] | None = None, syntax_registry: SyntaxRegistry | None = None):
|
39
|
+
super().__init__(syntax_registry=syntax_registry)
|
40
|
+
self.columns = columns or []
|
41
|
+
|
42
|
+
@override
|
43
|
+
def to_markdown(self) -> str:
|
44
|
+
column_list_syntax = self._syntax_registry.get_column_list_syntax()
|
45
|
+
if not self.columns:
|
46
|
+
return f"{column_list_syntax.start_delimiter}\n{column_list_syntax.end_delimiter}"
|
47
|
+
|
48
|
+
column_parts = [column.to_markdown() for column in self.columns]
|
49
|
+
columns_content = "\n\n".join(column_parts)
|
50
|
+
|
51
|
+
return f"{column_list_syntax.start_delimiter}\n{columns_content}\n{column_list_syntax.end_delimiter}"
|
@@ -0,0 +1,14 @@
|
|
1
|
+
from typing import override
|
2
|
+
|
3
|
+
from notionary.page.content.markdown.nodes.base import MarkdownNode
|
4
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
5
|
+
|
6
|
+
|
7
|
+
class DividerMarkdownNode(MarkdownNode):
|
8
|
+
def __init__(self, syntax_registry: SyntaxRegistry | None = None) -> None:
|
9
|
+
super().__init__(syntax_registry=syntax_registry)
|
10
|
+
|
11
|
+
@override
|
12
|
+
def to_markdown(self) -> str:
|
13
|
+
divider_syntax = self._syntax_registry.get_divider_syntax()
|
14
|
+
return divider_syntax.start_delimiter
|