notionary 0.2.27__py3-none-any.whl → 0.3.0__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/__init__.py +4 -4
- notionary/blocks/client.py +90 -216
- notionary/blocks/enums.py +167 -0
- notionary/blocks/rich_text/markdown_rich_text_converter.py +280 -0
- notionary/blocks/rich_text/models.py +178 -0
- notionary/blocks/rich_text/name_id_resolver/__init__.py +13 -0
- notionary/blocks/rich_text/name_id_resolver/data_source.py +32 -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 +144 -0
- notionary/blocks/rich_text/rich_text_patterns.py +42 -0
- notionary/blocks/schemas.py +778 -0
- notionary/comments/__init__.py +1 -22
- notionary/comments/client.py +52 -187
- notionary/comments/factory.py +38 -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 +104 -0
- notionary/data_source/properties/schemas.py +402 -0
- notionary/data_source/query/builder.py +448 -0
- notionary/data_source/query/resolver.py +114 -0
- notionary/data_source/query/schema.py +302 -0
- notionary/data_source/query/validator.py +73 -0
- notionary/data_source/schema/registry.py +104 -0
- notionary/data_source/schema/service.py +136 -0
- notionary/data_source/schemas.py +27 -0
- notionary/data_source/service.py +377 -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 +168 -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 +57 -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 +204 -0
- notionary/http/models.py +50 -0
- notionary/page/blocks/client.py +1 -0
- notionary/page/content/factory.py +73 -0
- notionary/page/content/markdown/__init__.py +5 -0
- notionary/page/content/markdown/builder.py +226 -0
- notionary/page/content/markdown/nodes/__init__.py +52 -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 +41 -0
- notionary/page/content/markdown/nodes/callout.py +34 -0
- notionary/page/content/markdown/nodes/code.py +28 -0
- notionary/page/content/markdown/nodes/columns.py +69 -0
- notionary/page/content/markdown/nodes/container.py +64 -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 +36 -0
- notionary/page/content/markdown/nodes/image.py +23 -0
- notionary/page/content/markdown/nodes/mixins/__init__.py +5 -0
- notionary/page/content/markdown/nodes/mixins/caption.py +12 -0
- notionary/page/content/markdown/nodes/numbered_list.py +38 -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 +27 -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 +38 -0
- notionary/page/content/markdown/nodes/toggle.py +27 -0
- notionary/page/content/markdown/nodes/video.py +23 -0
- notionary/page/content/parser/context.py +126 -0
- notionary/page/content/parser/factory.py +210 -0
- notionary/page/content/parser/parsers/__init__.py +58 -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 +85 -0
- notionary/page/content/parser/parsers/callout.py +100 -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 +76 -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 +115 -0
- notionary/page/content/parser/parsers/image.py +42 -0
- notionary/page/content/parser/parsers/numbered_list.py +89 -0
- notionary/page/content/parser/parsers/paragraph.py +37 -0
- notionary/page/content/parser/parsers/pdf.py +42 -0
- notionary/page/content/parser/parsers/quote.py +125 -0
- notionary/page/content/parser/parsers/space.py +41 -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 +96 -0
- notionary/page/content/parser/parsers/toggle.py +70 -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 +95 -0
- notionary/page/content/parser/post_processing/handlers/rich_text_length_truncation.py +114 -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 +11 -0
- notionary/page/content/parser/pre_processsing/handlers/column_syntax.py +130 -0
- notionary/page/content/parser/pre_processsing/handlers/indentation.py +84 -0
- notionary/page/content/parser/pre_processsing/handlers/port.py +7 -0
- notionary/page/content/parser/pre_processsing/handlers/whitespace.py +73 -0
- notionary/page/content/parser/pre_processsing/service.py +15 -0
- notionary/page/content/parser/service.py +78 -0
- notionary/page/content/renderer/context.py +51 -0
- notionary/page/content/renderer/factory.py +231 -0
- notionary/page/content/renderer/post_processing/handlers/__init__.py +5 -0
- notionary/page/content/renderer/post_processing/handlers/numbered_list.py +156 -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 +55 -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 +50 -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 +53 -0
- notionary/page/content/renderer/renderers/column_list.py +44 -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 +95 -0
- notionary/page/content/renderer/renderers/image.py +31 -0
- notionary/page/content/renderer/renderers/numbered_list.py +42 -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 +52 -0
- notionary/page/content/renderer/renderers/video.py +31 -0
- notionary/page/content/renderer/service.py +50 -0
- notionary/page/content/service.py +68 -0
- notionary/page/content/syntax/__init__.py +4 -0
- notionary/page/content/syntax/grammar.py +10 -0
- notionary/page/content/syntax/models.py +66 -0
- notionary/page/content/syntax/registry.py +393 -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 +308 -0
- notionary/page/properties/service.py +261 -0
- notionary/page/schemas.py +13 -0
- notionary/page/service.py +225 -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/shared/typings.py +3 -0
- notionary/user/__init__.py +4 -8
- notionary/user/base.py +138 -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/date.py +51 -0
- notionary/utils/decorators.py +122 -0
- notionary/utils/fuzzy.py +68 -0
- notionary/utils/mixins/logging.py +58 -0
- notionary/utils/pagination.py +100 -0
- notionary/utils/uuid_utils.py +20 -0
- notionary/workspace/__init__.py +4 -0
- notionary/workspace/client.py +62 -0
- notionary/workspace/query/__init__.py +3 -0
- notionary/workspace/query/builder.py +60 -0
- notionary/workspace/query/models.py +61 -0
- notionary/workspace/query/service.py +100 -0
- notionary/workspace/schemas.py +21 -0
- notionary/workspace/service.py +116 -0
- notionary-0.3.0.dist-info/METADATA +201 -0
- notionary-0.3.0.dist-info/RECORD +209 -0
- {notionary-0.2.27.dist-info → notionary-0.3.0.dist-info}/WHEEL +1 -1
- {notionary-0.2.27.dist-info → notionary-0.3.0.dist-info/licenses}/LICENSE +9 -9
- notionary/base_notion_client.py +0 -219
- 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/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/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/logging_mixin.py +0 -59
- 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/METADATA +0 -270
- notionary-0.2.27.dist-info/RECORD +0 -202
- /notionary/{database → user}/factory.py +0 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
from notionary.blocks.rich_text.markdown_rich_text_converter import (
|
|
2
|
+
MarkdownRichTextConverter,
|
|
3
|
+
)
|
|
4
|
+
from notionary.page.content.parser.parsers import (
|
|
5
|
+
AudioParser,
|
|
6
|
+
BookmarkParser,
|
|
7
|
+
BreadcrumbParser,
|
|
8
|
+
BulletedListParser,
|
|
9
|
+
CalloutParser,
|
|
10
|
+
CaptionParser,
|
|
11
|
+
CodeParser,
|
|
12
|
+
ColumnListParser,
|
|
13
|
+
ColumnParser,
|
|
14
|
+
DividerParser,
|
|
15
|
+
EmbedParser,
|
|
16
|
+
EquationParser,
|
|
17
|
+
FileParser,
|
|
18
|
+
HeadingParser,
|
|
19
|
+
ImageParser,
|
|
20
|
+
LineParser,
|
|
21
|
+
NumberedListParser,
|
|
22
|
+
ParagraphParser,
|
|
23
|
+
PdfParser,
|
|
24
|
+
QuoteParser,
|
|
25
|
+
SpaceParser,
|
|
26
|
+
TableOfContentsParser,
|
|
27
|
+
TableParser,
|
|
28
|
+
TodoParser,
|
|
29
|
+
ToggleParser,
|
|
30
|
+
VideoParser,
|
|
31
|
+
)
|
|
32
|
+
from notionary.page.content.syntax import SyntaxRegistry
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ConverterChainFactory:
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
rich_text_converter: MarkdownRichTextConverter | None = None,
|
|
39
|
+
syntax_registry: SyntaxRegistry | None = None,
|
|
40
|
+
) -> None:
|
|
41
|
+
self._rich_text_converter = rich_text_converter or MarkdownRichTextConverter()
|
|
42
|
+
self._syntax_registry = syntax_registry or SyntaxRegistry()
|
|
43
|
+
|
|
44
|
+
def create(self) -> LineParser:
|
|
45
|
+
# multi-line (structural) blocks
|
|
46
|
+
code_parser = self._create_code_parser()
|
|
47
|
+
equation_parser = self._create_equation_parser()
|
|
48
|
+
table_parser = self._create_table_parser()
|
|
49
|
+
column_parser = self._create_column_parser()
|
|
50
|
+
column_list_parser = self._create_column_list_parser()
|
|
51
|
+
toggle_parser = self._create_toggle_parser()
|
|
52
|
+
|
|
53
|
+
# Single-line blocks
|
|
54
|
+
divider_parser = self._create_divider_parser()
|
|
55
|
+
breadcrumb_parser = self._create_breadcrumb_parser()
|
|
56
|
+
table_of_contents_parser = self._create_table_of_contents_parser()
|
|
57
|
+
space_parser = self._create_space_parser()
|
|
58
|
+
heading_parser = self._create_heading_parser()
|
|
59
|
+
quote_parser = self._create_quote_parser()
|
|
60
|
+
callout_parser = self._create_callout_parser()
|
|
61
|
+
todo_parser = self._create_todo_parser()
|
|
62
|
+
bulleted_list_parser = self._create_bulleted_list_parser()
|
|
63
|
+
numbered_list_parser = self._create_numbered_list_parser()
|
|
64
|
+
|
|
65
|
+
# Media blocks
|
|
66
|
+
bookmark_parser = self._create_bookmark_parser()
|
|
67
|
+
embed_parser = self._create_embed_parser()
|
|
68
|
+
image_parser = self._create_image_parser()
|
|
69
|
+
video_parser = self._create_video_parser()
|
|
70
|
+
audio_parser = self._create_audio_parser()
|
|
71
|
+
file_parser = self._create_file_parser()
|
|
72
|
+
pdf_parser = self._create_pdf_parser()
|
|
73
|
+
|
|
74
|
+
# Caption and Fallback
|
|
75
|
+
caption_parser = self._create_caption_parser()
|
|
76
|
+
paragraph_parser = self._create_paragraph_parser()
|
|
77
|
+
|
|
78
|
+
(
|
|
79
|
+
code_parser.set_next(equation_parser)
|
|
80
|
+
.set_next(table_parser)
|
|
81
|
+
.set_next(column_parser)
|
|
82
|
+
.set_next(column_list_parser)
|
|
83
|
+
.set_next(toggle_parser)
|
|
84
|
+
.set_next(divider_parser)
|
|
85
|
+
.set_next(breadcrumb_parser)
|
|
86
|
+
.set_next(table_of_contents_parser)
|
|
87
|
+
.set_next(space_parser)
|
|
88
|
+
.set_next(heading_parser)
|
|
89
|
+
.set_next(quote_parser)
|
|
90
|
+
.set_next(callout_parser)
|
|
91
|
+
.set_next(todo_parser)
|
|
92
|
+
.set_next(bulleted_list_parser)
|
|
93
|
+
.set_next(numbered_list_parser)
|
|
94
|
+
.set_next(bookmark_parser)
|
|
95
|
+
.set_next(embed_parser)
|
|
96
|
+
.set_next(image_parser)
|
|
97
|
+
.set_next(video_parser)
|
|
98
|
+
.set_next(audio_parser)
|
|
99
|
+
.set_next(file_parser)
|
|
100
|
+
.set_next(pdf_parser)
|
|
101
|
+
.set_next(caption_parser)
|
|
102
|
+
.set_next(paragraph_parser)
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
return code_parser
|
|
106
|
+
|
|
107
|
+
def _create_code_parser(self) -> CodeParser:
|
|
108
|
+
return CodeParser(
|
|
109
|
+
syntax_registry=self._syntax_registry,
|
|
110
|
+
rich_text_converter=self._rich_text_converter,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
def _create_equation_parser(self) -> EquationParser:
|
|
114
|
+
return EquationParser(syntax_registry=self._syntax_registry)
|
|
115
|
+
|
|
116
|
+
def _create_table_parser(self) -> TableParser:
|
|
117
|
+
return TableParser(
|
|
118
|
+
syntax_registry=self._syntax_registry,
|
|
119
|
+
rich_text_converter=self._rich_text_converter,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def _create_column_parser(self) -> ColumnParser:
|
|
123
|
+
return ColumnParser(syntax_registry=self._syntax_registry)
|
|
124
|
+
|
|
125
|
+
def _create_column_list_parser(self) -> ColumnListParser:
|
|
126
|
+
return ColumnListParser(syntax_registry=self._syntax_registry)
|
|
127
|
+
|
|
128
|
+
def _create_toggle_parser(self) -> ToggleParser:
|
|
129
|
+
return ToggleParser(
|
|
130
|
+
syntax_registry=self._syntax_registry,
|
|
131
|
+
rich_text_converter=self._rich_text_converter,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
def _create_divider_parser(self) -> DividerParser:
|
|
135
|
+
return DividerParser(syntax_registry=self._syntax_registry)
|
|
136
|
+
|
|
137
|
+
def _create_breadcrumb_parser(self) -> BreadcrumbParser:
|
|
138
|
+
return BreadcrumbParser(syntax_registry=self._syntax_registry)
|
|
139
|
+
|
|
140
|
+
def _create_table_of_contents_parser(self) -> TableOfContentsParser:
|
|
141
|
+
return TableOfContentsParser(syntax_registry=self._syntax_registry)
|
|
142
|
+
|
|
143
|
+
def _create_space_parser(self) -> SpaceParser:
|
|
144
|
+
return SpaceParser(syntax_registry=self._syntax_registry)
|
|
145
|
+
|
|
146
|
+
def _create_heading_parser(self) -> HeadingParser:
|
|
147
|
+
return HeadingParser(
|
|
148
|
+
syntax_registry=self._syntax_registry,
|
|
149
|
+
rich_text_converter=self._rich_text_converter,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def _create_quote_parser(self) -> QuoteParser:
|
|
153
|
+
return QuoteParser(
|
|
154
|
+
syntax_registry=self._syntax_registry,
|
|
155
|
+
rich_text_converter=self._rich_text_converter,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
def _create_callout_parser(self) -> CalloutParser:
|
|
159
|
+
return CalloutParser(
|
|
160
|
+
syntax_registry=self._syntax_registry,
|
|
161
|
+
rich_text_converter=self._rich_text_converter,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
def _create_todo_parser(self) -> TodoParser:
|
|
165
|
+
return TodoParser(
|
|
166
|
+
syntax_registry=self._syntax_registry,
|
|
167
|
+
rich_text_converter=self._rich_text_converter,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
def _create_bulleted_list_parser(self) -> BulletedListParser:
|
|
171
|
+
return BulletedListParser(
|
|
172
|
+
syntax_registry=self._syntax_registry,
|
|
173
|
+
rich_text_converter=self._rich_text_converter,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
def _create_numbered_list_parser(self) -> NumberedListParser:
|
|
177
|
+
return NumberedListParser(
|
|
178
|
+
syntax_registry=self._syntax_registry,
|
|
179
|
+
rich_text_converter=self._rich_text_converter,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
def _create_bookmark_parser(self) -> BookmarkParser:
|
|
183
|
+
return BookmarkParser(syntax_registry=self._syntax_registry)
|
|
184
|
+
|
|
185
|
+
def _create_embed_parser(self) -> EmbedParser:
|
|
186
|
+
return EmbedParser(syntax_registry=self._syntax_registry)
|
|
187
|
+
|
|
188
|
+
def _create_image_parser(self) -> ImageParser:
|
|
189
|
+
return ImageParser(syntax_registry=self._syntax_registry)
|
|
190
|
+
|
|
191
|
+
def _create_video_parser(self) -> VideoParser:
|
|
192
|
+
return VideoParser(syntax_registry=self._syntax_registry)
|
|
193
|
+
|
|
194
|
+
def _create_audio_parser(self) -> AudioParser:
|
|
195
|
+
return AudioParser(syntax_registry=self._syntax_registry)
|
|
196
|
+
|
|
197
|
+
def _create_file_parser(self) -> FileParser:
|
|
198
|
+
return FileParser(syntax_registry=self._syntax_registry)
|
|
199
|
+
|
|
200
|
+
def _create_pdf_parser(self) -> PdfParser:
|
|
201
|
+
return PdfParser(syntax_registry=self._syntax_registry)
|
|
202
|
+
|
|
203
|
+
def _create_caption_parser(self) -> CaptionParser:
|
|
204
|
+
return CaptionParser(
|
|
205
|
+
syntax_registry=self._syntax_registry,
|
|
206
|
+
rich_text_converter=self._rich_text_converter,
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
def _create_paragraph_parser(self) -> ParagraphParser:
|
|
210
|
+
return ParagraphParser(rich_text_converter=self._rich_text_converter)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from ..context import BlockParsingContext, ParentBlockContext
|
|
2
|
+
from .audio import AudioParser
|
|
3
|
+
from .base import LineParser
|
|
4
|
+
from .bookmark import BookmarkParser
|
|
5
|
+
from .breadcrumb import BreadcrumbParser
|
|
6
|
+
from .bulleted_list import BulletedListParser
|
|
7
|
+
from .callout import CalloutParser
|
|
8
|
+
from .caption import CaptionParser
|
|
9
|
+
from .code import CodeParser
|
|
10
|
+
from .column import ColumnParser
|
|
11
|
+
from .column_list import ColumnListParser
|
|
12
|
+
from .divider import DividerParser
|
|
13
|
+
from .embed import EmbedParser
|
|
14
|
+
from .equation import EquationParser
|
|
15
|
+
from .file import FileParser
|
|
16
|
+
from .heading import HeadingParser
|
|
17
|
+
from .image import ImageParser
|
|
18
|
+
from .numbered_list import NumberedListParser
|
|
19
|
+
from .paragraph import ParagraphParser
|
|
20
|
+
from .pdf import PdfParser
|
|
21
|
+
from .quote import QuoteParser
|
|
22
|
+
from .space import SpaceParser
|
|
23
|
+
from .table import TableParser
|
|
24
|
+
from .table_of_contents import TableOfContentsParser
|
|
25
|
+
from .todo import TodoParser
|
|
26
|
+
from .toggle import ToggleParser
|
|
27
|
+
from .video import VideoParser
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"AudioParser",
|
|
31
|
+
"BlockParsingContext",
|
|
32
|
+
"BookmarkParser",
|
|
33
|
+
"BreadcrumbParser",
|
|
34
|
+
"BulletedListParser",
|
|
35
|
+
"CalloutParser",
|
|
36
|
+
"CaptionParser",
|
|
37
|
+
"CodeParser",
|
|
38
|
+
"ColumnListParser",
|
|
39
|
+
"ColumnParser",
|
|
40
|
+
"DividerParser",
|
|
41
|
+
"EmbedParser",
|
|
42
|
+
"EquationParser",
|
|
43
|
+
"FileParser",
|
|
44
|
+
"HeadingParser",
|
|
45
|
+
"ImageParser",
|
|
46
|
+
"LineParser",
|
|
47
|
+
"NumberedListParser",
|
|
48
|
+
"ParagraphParser",
|
|
49
|
+
"ParentBlockContext",
|
|
50
|
+
"PdfParser",
|
|
51
|
+
"QuoteParser",
|
|
52
|
+
"SpaceParser",
|
|
53
|
+
"TableOfContentsParser",
|
|
54
|
+
"TableParser",
|
|
55
|
+
"TodoParser",
|
|
56
|
+
"ToggleParser",
|
|
57
|
+
"VideoParser",
|
|
58
|
+
]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from typing import override
|
|
2
|
+
|
|
3
|
+
from notionary.blocks.schemas import (
|
|
4
|
+
CreateAudioBlock,
|
|
5
|
+
ExternalFile,
|
|
6
|
+
FileData,
|
|
7
|
+
FileType,
|
|
8
|
+
)
|
|
9
|
+
from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
|
|
10
|
+
from notionary.page.content.syntax import SyntaxRegistry
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AudioParser(LineParser):
|
|
14
|
+
def __init__(self, syntax_registry: SyntaxRegistry) -> None:
|
|
15
|
+
super().__init__(syntax_registry)
|
|
16
|
+
self._syntax = syntax_registry.get_audio_syntax()
|
|
17
|
+
|
|
18
|
+
@override
|
|
19
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
|
20
|
+
if context.is_inside_parent_context():
|
|
21
|
+
return False
|
|
22
|
+
return self._syntax.regex_pattern.search(context.line) is not None
|
|
23
|
+
|
|
24
|
+
@override
|
|
25
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
|
26
|
+
url = self._extract_url(context.line)
|
|
27
|
+
if url is None:
|
|
28
|
+
return
|
|
29
|
+
|
|
30
|
+
audio_data = FileData(
|
|
31
|
+
type=FileType.EXTERNAL,
|
|
32
|
+
external=ExternalFile(url=url),
|
|
33
|
+
caption=[],
|
|
34
|
+
)
|
|
35
|
+
block = CreateAudioBlock(audio=audio_data)
|
|
36
|
+
context.result_blocks.append(block)
|
|
37
|
+
|
|
38
|
+
def _extract_url(self, line: str) -> str | None:
|
|
39
|
+
match = self._syntax.regex_pattern.search(line)
|
|
40
|
+
return match.group(1).strip() if match else None
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
|
|
5
|
+
from notionary.page.content.parser.context import BlockParsingContext
|
|
6
|
+
from notionary.page.content.syntax import SyntaxRegistry
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class LineParser(ABC):
|
|
10
|
+
def __init__(self, syntax_registry: SyntaxRegistry | None = None) -> None:
|
|
11
|
+
self._next_handler: LineParser | None = None
|
|
12
|
+
self._syntax_registry = syntax_registry
|
|
13
|
+
|
|
14
|
+
def set_next(self, handler: LineParser) -> LineParser:
|
|
15
|
+
self._next_handler = handler
|
|
16
|
+
return handler
|
|
17
|
+
|
|
18
|
+
async def handle(self, context: BlockParsingContext) -> None:
|
|
19
|
+
if self._can_handle(context):
|
|
20
|
+
await self._process(context)
|
|
21
|
+
elif self._next_handler:
|
|
22
|
+
await self._next_handler.handle(context)
|
|
23
|
+
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
|
30
|
+
pass
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Parser for bookmark blocks."""
|
|
2
|
+
|
|
3
|
+
from typing import override
|
|
4
|
+
|
|
5
|
+
from notionary.blocks.schemas import BookmarkData, CreateBookmarkBlock
|
|
6
|
+
from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
|
|
7
|
+
from notionary.page.content.syntax import SyntaxRegistry
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BookmarkParser(LineParser):
|
|
11
|
+
def __init__(self, syntax_registry: SyntaxRegistry) -> None:
|
|
12
|
+
super().__init__(syntax_registry)
|
|
13
|
+
self._syntax = syntax_registry.get_bookmark_syntax()
|
|
14
|
+
|
|
15
|
+
@override
|
|
16
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
|
17
|
+
if context.is_inside_parent_context():
|
|
18
|
+
return False
|
|
19
|
+
return self._syntax.regex_pattern.search(context.line) is not None
|
|
20
|
+
|
|
21
|
+
@override
|
|
22
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
|
23
|
+
url = self._extract_url(context.line)
|
|
24
|
+
if not url:
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
bookmark_data = BookmarkData(url=url, caption=[])
|
|
28
|
+
block = CreateBookmarkBlock(bookmark=bookmark_data)
|
|
29
|
+
context.result_blocks.append(block)
|
|
30
|
+
|
|
31
|
+
def _extract_url(self, line: str) -> str | None:
|
|
32
|
+
match = self._syntax.regex_pattern.search(line)
|
|
33
|
+
return match.group(1) if match else None
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from typing import override
|
|
2
|
+
|
|
3
|
+
from notionary.blocks.schemas import BreadcrumbData, CreateBreadcrumbBlock
|
|
4
|
+
from notionary.page.content.parser.parsers.base import (
|
|
5
|
+
BlockParsingContext,
|
|
6
|
+
LineParser,
|
|
7
|
+
)
|
|
8
|
+
from notionary.page.content.syntax import SyntaxRegistry
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BreadcrumbParser(LineParser):
|
|
12
|
+
def __init__(self, syntax_registry: SyntaxRegistry) -> None:
|
|
13
|
+
super().__init__(syntax_registry)
|
|
14
|
+
self._syntax = syntax_registry.get_breadcrumb_syntax()
|
|
15
|
+
|
|
16
|
+
@override
|
|
17
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
|
18
|
+
if context.is_inside_parent_context():
|
|
19
|
+
return False
|
|
20
|
+
return self._is_breadcrumb(context.line)
|
|
21
|
+
|
|
22
|
+
@override
|
|
23
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
|
24
|
+
block = self._create_breadcrumb_block()
|
|
25
|
+
if block:
|
|
26
|
+
context.result_blocks.append(block)
|
|
27
|
+
|
|
28
|
+
def _is_breadcrumb(self, line: str) -> bool:
|
|
29
|
+
return self._syntax.regex_pattern.match(line) is not None
|
|
30
|
+
|
|
31
|
+
def _create_breadcrumb_block(self) -> CreateBreadcrumbBlock:
|
|
32
|
+
breadcrumb_data = BreadcrumbData()
|
|
33
|
+
return CreateBreadcrumbBlock(breadcrumb=breadcrumb_data)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from typing import override
|
|
2
|
+
|
|
3
|
+
from notionary.blocks.rich_text.markdown_rich_text_converter import (
|
|
4
|
+
MarkdownRichTextConverter,
|
|
5
|
+
)
|
|
6
|
+
from notionary.blocks.schemas import CreateBulletedListItemBlock, CreateBulletedListItemData
|
|
7
|
+
from notionary.page.content.parser.parsers.base import (
|
|
8
|
+
BlockParsingContext,
|
|
9
|
+
LineParser,
|
|
10
|
+
)
|
|
11
|
+
from notionary.page.content.syntax import SyntaxRegistry
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BulletedListParser(LineParser):
|
|
15
|
+
def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
|
|
16
|
+
super().__init__(syntax_registry)
|
|
17
|
+
self._syntax = syntax_registry.get_bulleted_list_syntax()
|
|
18
|
+
self._rich_text_converter = rich_text_converter
|
|
19
|
+
|
|
20
|
+
@override
|
|
21
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
|
22
|
+
if context.is_inside_parent_context():
|
|
23
|
+
return False
|
|
24
|
+
return self._is_bulleted_list_line(context.line)
|
|
25
|
+
|
|
26
|
+
def _is_bulleted_list_line(self, line: str) -> bool:
|
|
27
|
+
return self._syntax.regex_pattern.match(line) is not None
|
|
28
|
+
|
|
29
|
+
@override
|
|
30
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
|
31
|
+
block = await self._create_bulleted_list_block(context.line)
|
|
32
|
+
if not block:
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
await self._process_nested_children(block, context)
|
|
36
|
+
context.result_blocks.append(block)
|
|
37
|
+
|
|
38
|
+
async def _process_nested_children(self, block: CreateBulletedListItemBlock, context: BlockParsingContext) -> None:
|
|
39
|
+
child_lines = self._collect_child_lines(context)
|
|
40
|
+
if not child_lines:
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
child_blocks = await self._parse_child_blocks(child_lines, context)
|
|
44
|
+
if child_blocks:
|
|
45
|
+
block.bulleted_list_item.children = child_blocks
|
|
46
|
+
|
|
47
|
+
context.lines_consumed = len(child_lines)
|
|
48
|
+
|
|
49
|
+
def _collect_child_lines(self, context: BlockParsingContext) -> list[str]:
|
|
50
|
+
parent_indent_level = context.get_line_indentation_level()
|
|
51
|
+
return context.collect_indented_child_lines(parent_indent_level)
|
|
52
|
+
|
|
53
|
+
async def _parse_child_blocks(
|
|
54
|
+
self, child_lines: list[str], context: BlockParsingContext
|
|
55
|
+
) -> list[CreateBulletedListItemBlock]:
|
|
56
|
+
stripped_lines = self._remove_parent_indentation(child_lines, context)
|
|
57
|
+
children_text = self._convert_lines_to_text(stripped_lines)
|
|
58
|
+
return await context.parse_nested_markdown(children_text)
|
|
59
|
+
|
|
60
|
+
def _remove_parent_indentation(self, lines: list[str], context: BlockParsingContext) -> list[str]:
|
|
61
|
+
return context.strip_indentation_level(lines, levels=1)
|
|
62
|
+
|
|
63
|
+
def _convert_lines_to_text(self, lines: list[str]) -> str:
|
|
64
|
+
return "\n".join(lines)
|
|
65
|
+
|
|
66
|
+
async def _create_bulleted_list_block(self, text: str) -> CreateBulletedListItemBlock | None:
|
|
67
|
+
content = self._extract_list_content(text)
|
|
68
|
+
if content is None:
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
rich_text = await self._convert_to_rich_text(content)
|
|
72
|
+
return self._build_block(rich_text)
|
|
73
|
+
|
|
74
|
+
def _extract_list_content(self, text: str) -> str | None:
|
|
75
|
+
match = self._syntax.regex_pattern.match(text)
|
|
76
|
+
if not match:
|
|
77
|
+
return None
|
|
78
|
+
return match.group(2)
|
|
79
|
+
|
|
80
|
+
async def _convert_to_rich_text(self, content: str):
|
|
81
|
+
return await self._rich_text_converter.to_rich_text(content)
|
|
82
|
+
|
|
83
|
+
def _build_block(self, rich_text) -> CreateBulletedListItemBlock:
|
|
84
|
+
bulleted_list_content = CreateBulletedListItemData(rich_text=rich_text)
|
|
85
|
+
return CreateBulletedListItemBlock(bulleted_list_item=bulleted_list_content)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import override
|
|
3
|
+
|
|
4
|
+
from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
|
|
5
|
+
from notionary.blocks.schemas import CreateCalloutBlock, CreateCalloutData
|
|
6
|
+
from notionary.page.content.parser.parsers.base import (
|
|
7
|
+
BlockParsingContext,
|
|
8
|
+
LineParser,
|
|
9
|
+
)
|
|
10
|
+
from notionary.page.content.syntax import SyntaxRegistry
|
|
11
|
+
from notionary.shared.models.icon import EmojiIcon
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CalloutParser(LineParser):
|
|
15
|
+
DEFAULT_EMOJI = "💡"
|
|
16
|
+
|
|
17
|
+
def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
|
|
18
|
+
super().__init__(syntax_registry)
|
|
19
|
+
self._syntax = syntax_registry.get_callout_syntax()
|
|
20
|
+
self._pattern = self._syntax.regex_pattern
|
|
21
|
+
self._rich_text_converter = rich_text_converter
|
|
22
|
+
|
|
23
|
+
@override
|
|
24
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
|
25
|
+
return self._pattern.search(context.line) is not None
|
|
26
|
+
|
|
27
|
+
@override
|
|
28
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
|
29
|
+
block = await self._create_callout_block(context.line)
|
|
30
|
+
if not block:
|
|
31
|
+
return
|
|
32
|
+
|
|
33
|
+
await self._process_nested_children(block, context)
|
|
34
|
+
|
|
35
|
+
if self._is_nested_in_parent_context(context):
|
|
36
|
+
context.parent_stack[-1].add_child_block(block)
|
|
37
|
+
else:
|
|
38
|
+
context.result_blocks.append(block)
|
|
39
|
+
|
|
40
|
+
async def _process_nested_children(self, block: CreateCalloutBlock, context: BlockParsingContext) -> None:
|
|
41
|
+
child_lines = self._collect_child_lines(context)
|
|
42
|
+
if not child_lines:
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
child_blocks = await self._parse_child_blocks(child_lines, context)
|
|
46
|
+
if child_blocks:
|
|
47
|
+
block.callout.children = child_blocks
|
|
48
|
+
|
|
49
|
+
context.lines_consumed = len(child_lines)
|
|
50
|
+
|
|
51
|
+
def _collect_child_lines(self, context: BlockParsingContext) -> list[str]:
|
|
52
|
+
parent_indent_level = context.get_line_indentation_level()
|
|
53
|
+
return context.collect_indented_child_lines(parent_indent_level)
|
|
54
|
+
|
|
55
|
+
async def _parse_child_blocks(
|
|
56
|
+
self, child_lines: list[str], context: BlockParsingContext
|
|
57
|
+
) -> list[CreateCalloutBlock]:
|
|
58
|
+
stripped_lines = self._remove_parent_indentation(child_lines, context)
|
|
59
|
+
children_text = self._convert_lines_to_text(stripped_lines)
|
|
60
|
+
return await context.parse_nested_markdown(children_text)
|
|
61
|
+
|
|
62
|
+
def _remove_parent_indentation(self, lines: list[str], context: BlockParsingContext) -> list[str]:
|
|
63
|
+
return context.strip_indentation_level(lines, levels=1)
|
|
64
|
+
|
|
65
|
+
def _convert_lines_to_text(self, lines: list[str]) -> str:
|
|
66
|
+
return "\n".join(lines)
|
|
67
|
+
|
|
68
|
+
async def _create_callout_block(self, line: str) -> CreateCalloutBlock | None:
|
|
69
|
+
match = self._pattern.search(line)
|
|
70
|
+
if not match:
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
content, emoji = self._extract_content_and_emoji(match)
|
|
74
|
+
rich_text = await self._convert_to_rich_text(content)
|
|
75
|
+
return self._build_block(rich_text, emoji)
|
|
76
|
+
|
|
77
|
+
def _extract_content_and_emoji(self, match: re.Match[str]) -> tuple[str, str]:
|
|
78
|
+
inline_content = match.group(1)
|
|
79
|
+
if inline_content:
|
|
80
|
+
return inline_content.strip(), match.group(2) or self.DEFAULT_EMOJI
|
|
81
|
+
|
|
82
|
+
block_content = match.group(3)
|
|
83
|
+
if block_content:
|
|
84
|
+
return block_content.strip(), match.group(4) or self.DEFAULT_EMOJI
|
|
85
|
+
|
|
86
|
+
return "", self.DEFAULT_EMOJI
|
|
87
|
+
|
|
88
|
+
async def _convert_to_rich_text(self, content: str):
|
|
89
|
+
return await self._rich_text_converter.to_rich_text(content)
|
|
90
|
+
|
|
91
|
+
def _build_block(self, rich_text, emoji: str) -> CreateCalloutBlock:
|
|
92
|
+
callout_data = CreateCalloutData(
|
|
93
|
+
rich_text=rich_text,
|
|
94
|
+
icon=EmojiIcon(emoji=emoji),
|
|
95
|
+
children=[],
|
|
96
|
+
)
|
|
97
|
+
return CreateCalloutBlock(callout=callout_data)
|
|
98
|
+
|
|
99
|
+
def _is_nested_in_parent_context(self, context: BlockParsingContext) -> bool:
|
|
100
|
+
return bool(context.parent_stack)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from typing import override
|
|
2
|
+
|
|
3
|
+
from notionary.blocks.rich_text.markdown_rich_text_converter import (
|
|
4
|
+
MarkdownRichTextConverter,
|
|
5
|
+
)
|
|
6
|
+
from notionary.blocks.schemas import BlockCreatePayload
|
|
7
|
+
from notionary.page.content.parser.parsers.base import (
|
|
8
|
+
BlockParsingContext,
|
|
9
|
+
LineParser,
|
|
10
|
+
)
|
|
11
|
+
from notionary.page.content.syntax import SyntaxRegistry
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CaptionParser(LineParser):
|
|
15
|
+
def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
|
|
16
|
+
super().__init__(syntax_registry)
|
|
17
|
+
self._syntax = syntax_registry.get_caption_syntax()
|
|
18
|
+
self._rich_text_converter = rich_text_converter
|
|
19
|
+
|
|
20
|
+
@override
|
|
21
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
|
22
|
+
if context.is_inside_parent_context():
|
|
23
|
+
return False
|
|
24
|
+
|
|
25
|
+
if not self._syntax.regex_pattern.match(context.line):
|
|
26
|
+
return False
|
|
27
|
+
|
|
28
|
+
if not context.result_blocks:
|
|
29
|
+
return False
|
|
30
|
+
|
|
31
|
+
previous_block = context.result_blocks[-1]
|
|
32
|
+
return self._block_supports_caption(previous_block)
|
|
33
|
+
|
|
34
|
+
@override
|
|
35
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
|
36
|
+
caption_match = self._syntax.regex_pattern.match(context.line)
|
|
37
|
+
if not caption_match:
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
caption_text = caption_match.group(1)
|
|
41
|
+
caption_rich_text = await self._rich_text_converter.to_rich_text(caption_text)
|
|
42
|
+
|
|
43
|
+
previous_block = context.result_blocks[-1]
|
|
44
|
+
self._attach_caption_to_block(previous_block, caption_rich_text)
|
|
45
|
+
|
|
46
|
+
def _block_supports_caption(self, block: BlockCreatePayload) -> bool:
|
|
47
|
+
block_data = getattr(block, block.type.value, None)
|
|
48
|
+
if block_data is None:
|
|
49
|
+
return False
|
|
50
|
+
return hasattr(block_data, "caption")
|
|
51
|
+
|
|
52
|
+
def _attach_caption_to_block(self, block: BlockCreatePayload, caption_rich_text: list) -> None:
|
|
53
|
+
block_data = getattr(block, block.type.value)
|
|
54
|
+
if hasattr(block_data, "caption"):
|
|
55
|
+
block_data.caption = caption_rich_text
|