notionary 0.2.26__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.26.dist-info → notionary-0.2.28.dist-info}/METADATA +54 -49
- notionary-0.2.28.dist-info/RECORD +200 -0
- {notionary-0.2.26.dist-info → notionary-0.2.28.dist-info}/WHEEL +1 -1
- {notionary-0.2.26.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 -674
- 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.26.dist-info/RECORD +0 -202
@@ -0,0 +1,81 @@
|
|
1
|
+
from typing import override
|
2
|
+
|
3
|
+
from notionary.blocks.enums import BlockType
|
4
|
+
from notionary.blocks.schemas import BlockCreatePayload, CreateColumnListBlock, CreateColumnListData
|
5
|
+
from notionary.page.content.parser.context import ParentBlockContext
|
6
|
+
from notionary.page.content.parser.parsers.base import (
|
7
|
+
BlockParsingContext,
|
8
|
+
LineParser,
|
9
|
+
)
|
10
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
11
|
+
|
12
|
+
|
13
|
+
class ColumnListParser(LineParser):
|
14
|
+
def __init__(self, syntax_registry: SyntaxRegistry) -> None:
|
15
|
+
super().__init__(syntax_registry)
|
16
|
+
self._syntax = syntax_registry.get_column_list_syntax()
|
17
|
+
|
18
|
+
@override
|
19
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
20
|
+
return self._is_column_list_start(context) or self._is_column_list_end(context)
|
21
|
+
|
22
|
+
@override
|
23
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
24
|
+
if self._is_column_list_start(context):
|
25
|
+
await self._start_column_list(context)
|
26
|
+
elif self._is_column_list_end(context):
|
27
|
+
await self._finalize_column_list(context)
|
28
|
+
|
29
|
+
def _is_column_list_start(self, context: BlockParsingContext) -> bool:
|
30
|
+
return self._syntax.regex_pattern.match(context.line) is not None
|
31
|
+
|
32
|
+
def _is_column_list_end(self, context: BlockParsingContext) -> bool:
|
33
|
+
if not self._syntax.end_regex_pattern.match(context.line):
|
34
|
+
return False
|
35
|
+
|
36
|
+
if not context.parent_stack:
|
37
|
+
return False
|
38
|
+
|
39
|
+
current_parent = context.parent_stack[-1]
|
40
|
+
return isinstance(current_parent.block, CreateColumnListBlock)
|
41
|
+
|
42
|
+
async def _start_column_list(self, context: BlockParsingContext) -> None:
|
43
|
+
column_list_data = CreateColumnListData()
|
44
|
+
block = CreateColumnListBlock(column_list=column_list_data)
|
45
|
+
|
46
|
+
parent_context = ParentBlockContext(
|
47
|
+
block=block,
|
48
|
+
child_lines=[],
|
49
|
+
)
|
50
|
+
context.parent_stack.append(parent_context)
|
51
|
+
|
52
|
+
async def _finalize_column_list(self, context: BlockParsingContext) -> None:
|
53
|
+
column_list_context = context.parent_stack.pop()
|
54
|
+
await self._assign_column_list_children(column_list_context, context)
|
55
|
+
|
56
|
+
if context.parent_stack:
|
57
|
+
parent_context = context.parent_stack[-1]
|
58
|
+
parent_context.add_child_block(column_list_context.block)
|
59
|
+
else:
|
60
|
+
context.result_blocks.append(column_list_context.block)
|
61
|
+
|
62
|
+
async def _assign_column_list_children(
|
63
|
+
self, column_list_context: ParentBlockContext, context: BlockParsingContext
|
64
|
+
) -> None:
|
65
|
+
all_children = []
|
66
|
+
|
67
|
+
if column_list_context.child_lines:
|
68
|
+
children_text = "\n".join(column_list_context.child_lines)
|
69
|
+
text_blocks = await context.parse_nested_content(children_text)
|
70
|
+
all_children.extend(text_blocks)
|
71
|
+
|
72
|
+
if column_list_context.child_blocks:
|
73
|
+
all_children.extend(column_list_context.child_blocks)
|
74
|
+
|
75
|
+
column_children = self._filter_column_blocks(all_children)
|
76
|
+
column_list_context.block.column_list.children = column_children
|
77
|
+
|
78
|
+
def _filter_column_blocks(self, blocks: list[BlockCreatePayload]) -> list:
|
79
|
+
return [
|
80
|
+
block for block in blocks if block.type == BlockType.COLUMN and hasattr(block, "column") and block.column
|
81
|
+
]
|
@@ -0,0 +1,33 @@
|
|
1
|
+
from typing import override
|
2
|
+
|
3
|
+
from notionary.blocks.schemas import CreateDividerBlock, DividerData
|
4
|
+
from notionary.page.content.parser.parsers.base import (
|
5
|
+
BlockParsingContext,
|
6
|
+
LineParser,
|
7
|
+
)
|
8
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
9
|
+
|
10
|
+
|
11
|
+
class DividerParser(LineParser):
|
12
|
+
def __init__(self, syntax_registry: SyntaxRegistry) -> None:
|
13
|
+
super().__init__(syntax_registry)
|
14
|
+
self._syntax = syntax_registry.get_divider_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_divider(context.line)
|
21
|
+
|
22
|
+
@override
|
23
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
24
|
+
block = self._create_divider_block()
|
25
|
+
if block:
|
26
|
+
context.result_blocks.append(block)
|
27
|
+
|
28
|
+
def _is_divider(self, line: str) -> bool:
|
29
|
+
return self._syntax.regex_pattern.match(line) is not None
|
30
|
+
|
31
|
+
def _create_divider_block(self) -> CreateDividerBlock:
|
32
|
+
divider_data = DividerData()
|
33
|
+
return CreateDividerBlock(divider=divider_data)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
"""Parser for embed blocks."""
|
2
|
+
|
3
|
+
from typing import override
|
4
|
+
|
5
|
+
from notionary.blocks.schemas import CreateEmbedBlock, EmbedData
|
6
|
+
from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
|
7
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
8
|
+
|
9
|
+
|
10
|
+
class EmbedParser(LineParser):
|
11
|
+
def __init__(self, syntax_registry: SyntaxRegistry) -> None:
|
12
|
+
super().__init__(syntax_registry)
|
13
|
+
self._syntax = syntax_registry.get_embed_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
|
+
embed_data = EmbedData(url=url, caption=[])
|
28
|
+
block = CreateEmbedBlock(embed=embed_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,65 @@
|
|
1
|
+
from typing import override
|
2
|
+
|
3
|
+
from notionary.blocks.schemas import CreateEquationBlock, EquationData
|
4
|
+
from notionary.page.content.parser.parsers.base import (
|
5
|
+
BlockParsingContext,
|
6
|
+
LineParser,
|
7
|
+
)
|
8
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
9
|
+
|
10
|
+
|
11
|
+
class EquationParser(LineParser):
|
12
|
+
def __init__(self, syntax_registry: SyntaxRegistry) -> None:
|
13
|
+
super().__init__(syntax_registry)
|
14
|
+
self._syntax = syntax_registry.get_equation_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_equation_delimiter(context.line)
|
21
|
+
|
22
|
+
@override
|
23
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
24
|
+
equation_content = self._collect_equation_content(context)
|
25
|
+
lines_consumed = self._count_lines_consumed(context)
|
26
|
+
|
27
|
+
block = self._create_equation_block(opening_line=context.line, equation_lines=equation_content)
|
28
|
+
|
29
|
+
if block:
|
30
|
+
context.lines_consumed = lines_consumed
|
31
|
+
context.result_blocks.append(block)
|
32
|
+
|
33
|
+
def _is_equation_delimiter(self, line: str) -> bool:
|
34
|
+
return self._syntax.regex_pattern.match(line) is not None
|
35
|
+
|
36
|
+
def _collect_equation_content(self, context: BlockParsingContext) -> list[str]:
|
37
|
+
content_lines = []
|
38
|
+
|
39
|
+
for line in context.get_remaining_lines():
|
40
|
+
if self._is_equation_delimiter(line):
|
41
|
+
break
|
42
|
+
content_lines.append(line)
|
43
|
+
|
44
|
+
return content_lines
|
45
|
+
|
46
|
+
def _count_lines_consumed(self, context: BlockParsingContext) -> int:
|
47
|
+
for line_index, line in enumerate(context.get_remaining_lines()):
|
48
|
+
if self._is_equation_delimiter(line):
|
49
|
+
return line_index + 1
|
50
|
+
|
51
|
+
return len(context.get_remaining_lines())
|
52
|
+
|
53
|
+
def _create_equation_block(self, opening_line: str, equation_lines: list[str]) -> CreateEquationBlock | None:
|
54
|
+
if opening_line.strip() != self._syntax.start_delimiter:
|
55
|
+
return None
|
56
|
+
|
57
|
+
if not equation_lines:
|
58
|
+
return None
|
59
|
+
|
60
|
+
expression = "\n".join(equation_lines).strip()
|
61
|
+
|
62
|
+
if expression:
|
63
|
+
return CreateEquationBlock(equation=EquationData(expression=expression))
|
64
|
+
|
65
|
+
return None
|
@@ -0,0 +1,42 @@
|
|
1
|
+
"""Parser for file blocks."""
|
2
|
+
|
3
|
+
from typing import override
|
4
|
+
|
5
|
+
from notionary.blocks.schemas import (
|
6
|
+
CreateFileBlock,
|
7
|
+
ExternalFile,
|
8
|
+
FileData,
|
9
|
+
FileType,
|
10
|
+
)
|
11
|
+
from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
|
12
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
13
|
+
|
14
|
+
|
15
|
+
class FileParser(LineParser):
|
16
|
+
def __init__(self, syntax_registry: SyntaxRegistry) -> None:
|
17
|
+
super().__init__(syntax_registry)
|
18
|
+
self._syntax = syntax_registry.get_file_syntax()
|
19
|
+
|
20
|
+
@override
|
21
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
22
|
+
if context.is_inside_parent_context():
|
23
|
+
return False
|
24
|
+
return self._syntax.regex_pattern.search(context.line) is not None
|
25
|
+
|
26
|
+
@override
|
27
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
28
|
+
url = self._extract_url(context.line)
|
29
|
+
if not url:
|
30
|
+
return
|
31
|
+
|
32
|
+
file_data = FileData(
|
33
|
+
type=FileType.EXTERNAL,
|
34
|
+
external=ExternalFile(url=url),
|
35
|
+
caption=[],
|
36
|
+
)
|
37
|
+
block = CreateFileBlock(file=file_data)
|
38
|
+
context.result_blocks.append(block)
|
39
|
+
|
40
|
+
def _extract_url(self, line: str) -> str | None:
|
41
|
+
match = self._syntax.regex_pattern.search(line)
|
42
|
+
return match.group(1).strip() if match else None
|
@@ -0,0 +1,58 @@
|
|
1
|
+
from typing import override
|
2
|
+
|
3
|
+
from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
|
4
|
+
from notionary.blocks.schemas import (
|
5
|
+
BlockColor,
|
6
|
+
CreateHeading1Block,
|
7
|
+
CreateHeading2Block,
|
8
|
+
CreateHeading3Block,
|
9
|
+
CreateHeadingBlock,
|
10
|
+
CreateHeadingData,
|
11
|
+
)
|
12
|
+
from notionary.page.content.parser.parsers.base import (
|
13
|
+
BlockParsingContext,
|
14
|
+
LineParser,
|
15
|
+
)
|
16
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
17
|
+
|
18
|
+
|
19
|
+
class HeadingParser(LineParser):
|
20
|
+
def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
|
21
|
+
super().__init__(syntax_registry)
|
22
|
+
self._syntax = syntax_registry.get_heading_syntax()
|
23
|
+
self._rich_text_converter = rich_text_converter
|
24
|
+
|
25
|
+
@override
|
26
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
27
|
+
if context.is_inside_parent_context():
|
28
|
+
return False
|
29
|
+
return self._syntax.regex_pattern.match(context.line) is not None
|
30
|
+
|
31
|
+
@override
|
32
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
33
|
+
block = await self._create_heading_block(context.line)
|
34
|
+
if block:
|
35
|
+
context.result_blocks.append(block)
|
36
|
+
|
37
|
+
async def _create_heading_block(self, line: str) -> CreateHeadingBlock | None:
|
38
|
+
match = self._syntax.regex_pattern.match(line)
|
39
|
+
if not match:
|
40
|
+
return None
|
41
|
+
|
42
|
+
level = len(match.group(1))
|
43
|
+
if level < 1 or level > 3:
|
44
|
+
return None
|
45
|
+
|
46
|
+
content = match.group(2).strip()
|
47
|
+
if not content:
|
48
|
+
return None
|
49
|
+
|
50
|
+
rich_text = await self._rich_text_converter.to_rich_text(content)
|
51
|
+
heading_data = CreateHeadingData(rich_text=rich_text, color=BlockColor.DEFAULT, is_toggleable=False)
|
52
|
+
|
53
|
+
if level == 1:
|
54
|
+
return CreateHeading1Block(heading_1=heading_data)
|
55
|
+
elif level == 2:
|
56
|
+
return CreateHeading2Block(heading_2=heading_data)
|
57
|
+
else:
|
58
|
+
return CreateHeading3Block(heading_3=heading_data)
|
@@ -0,0 +1,42 @@
|
|
1
|
+
"""Parser for image blocks."""
|
2
|
+
|
3
|
+
from typing import override
|
4
|
+
|
5
|
+
from notionary.blocks.schemas import (
|
6
|
+
CreateImageBlock,
|
7
|
+
ExternalFile,
|
8
|
+
FileData,
|
9
|
+
FileType,
|
10
|
+
)
|
11
|
+
from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
|
12
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
13
|
+
|
14
|
+
|
15
|
+
class ImageParser(LineParser):
|
16
|
+
def __init__(self, syntax_registry: SyntaxRegistry) -> None:
|
17
|
+
super().__init__(syntax_registry)
|
18
|
+
self._syntax = syntax_registry.get_image_syntax()
|
19
|
+
|
20
|
+
@override
|
21
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
22
|
+
if context.is_inside_parent_context():
|
23
|
+
return False
|
24
|
+
return self._syntax.regex_pattern.search(context.line) is not None
|
25
|
+
|
26
|
+
@override
|
27
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
28
|
+
url = self._extract_url(context.line)
|
29
|
+
if not url:
|
30
|
+
return
|
31
|
+
|
32
|
+
image_data = FileData(
|
33
|
+
type=FileType.EXTERNAL,
|
34
|
+
external=ExternalFile(url=url),
|
35
|
+
caption=[],
|
36
|
+
)
|
37
|
+
block = CreateImageBlock(image=image_data)
|
38
|
+
context.result_blocks.append(block)
|
39
|
+
|
40
|
+
def _extract_url(self, line: str) -> str | None:
|
41
|
+
match = self._syntax.regex_pattern.search(line)
|
42
|
+
return match.group(1).strip() if match else None
|
@@ -0,0 +1,45 @@
|
|
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 (
|
7
|
+
BlockColor,
|
8
|
+
CreateNumberedListItemBlock,
|
9
|
+
NumberedListItemData,
|
10
|
+
)
|
11
|
+
from notionary.page.content.parser.parsers.base import (
|
12
|
+
BlockParsingContext,
|
13
|
+
LineParser,
|
14
|
+
)
|
15
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
16
|
+
|
17
|
+
|
18
|
+
class NumberedListParser(LineParser):
|
19
|
+
def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
|
20
|
+
super().__init__(syntax_registry)
|
21
|
+
self._syntax = syntax_registry.get_numbered_list_syntax()
|
22
|
+
self._rich_text_converter = rich_text_converter
|
23
|
+
|
24
|
+
@override
|
25
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
26
|
+
if context.is_inside_parent_context():
|
27
|
+
return False
|
28
|
+
return self._syntax.regex_pattern.match(context.line) is not None
|
29
|
+
|
30
|
+
@override
|
31
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
32
|
+
block = await self._create_numbered_list_block(context.line)
|
33
|
+
if block:
|
34
|
+
context.result_blocks.append(block)
|
35
|
+
|
36
|
+
async def _create_numbered_list_block(self, text: str) -> CreateNumberedListItemBlock | None:
|
37
|
+
match = self._syntax.regex_pattern.match(text)
|
38
|
+
if not match:
|
39
|
+
return None
|
40
|
+
|
41
|
+
content = match.group(3)
|
42
|
+
rich_text = await self._rich_text_converter.to_rich_text(content)
|
43
|
+
|
44
|
+
numbered_list_content = NumberedListItemData(rich_text=rich_text, color=BlockColor.DEFAULT)
|
45
|
+
return CreateNumberedListItemBlock(numbered_list_item=numbered_list_content)
|
@@ -0,0 +1,36 @@
|
|
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 BlockColor, CreateParagraphBlock, ParagraphData
|
7
|
+
from notionary.page.content.parser.parsers.base import (
|
8
|
+
BlockParsingContext,
|
9
|
+
LineParser,
|
10
|
+
)
|
11
|
+
|
12
|
+
|
13
|
+
class ParagraphParser(LineParser):
|
14
|
+
def __init__(self, rich_text_converter: MarkdownRichTextConverter) -> None:
|
15
|
+
super().__init__()
|
16
|
+
self._rich_text_converter = rich_text_converter
|
17
|
+
|
18
|
+
@override
|
19
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
20
|
+
if context.is_inside_parent_context():
|
21
|
+
return False
|
22
|
+
return bool(context.line)
|
23
|
+
|
24
|
+
@override
|
25
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
26
|
+
block = await self._create_paragraph_block(context.line)
|
27
|
+
if block:
|
28
|
+
context.result_blocks.append(block)
|
29
|
+
|
30
|
+
async def _create_paragraph_block(self, text: str) -> CreateParagraphBlock | None:
|
31
|
+
if not text:
|
32
|
+
return None
|
33
|
+
|
34
|
+
rich_text = await self._rich_text_converter.to_rich_text(text)
|
35
|
+
paragraph_content = ParagraphData(rich_text=rich_text, color=BlockColor.DEFAULT)
|
36
|
+
return CreateParagraphBlock(paragraph=paragraph_content)
|
@@ -0,0 +1,42 @@
|
|
1
|
+
"""Parser for PDF blocks."""
|
2
|
+
|
3
|
+
from typing import override
|
4
|
+
|
5
|
+
from notionary.blocks.schemas import (
|
6
|
+
CreatePdfBlock,
|
7
|
+
ExternalFile,
|
8
|
+
FileData,
|
9
|
+
FileType,
|
10
|
+
)
|
11
|
+
from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
|
12
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
13
|
+
|
14
|
+
|
15
|
+
class PdfParser(LineParser):
|
16
|
+
def __init__(self, syntax_registry: SyntaxRegistry) -> None:
|
17
|
+
super().__init__(syntax_registry)
|
18
|
+
self._syntax = syntax_registry.get_pdf_syntax()
|
19
|
+
|
20
|
+
@override
|
21
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
22
|
+
if context.is_inside_parent_context():
|
23
|
+
return False
|
24
|
+
return self._syntax.regex_pattern.search(context.line) is not None
|
25
|
+
|
26
|
+
@override
|
27
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
28
|
+
url = self._extract_url(context.line)
|
29
|
+
if not url:
|
30
|
+
return
|
31
|
+
|
32
|
+
pdf_data = FileData(
|
33
|
+
type=FileType.EXTERNAL,
|
34
|
+
external=ExternalFile(url=url),
|
35
|
+
caption=[],
|
36
|
+
)
|
37
|
+
block = CreatePdfBlock(pdf=pdf_data)
|
38
|
+
context.result_blocks.append(block)
|
39
|
+
|
40
|
+
def _extract_url(self, line: str) -> str | None:
|
41
|
+
match = self._syntax.regex_pattern.search(line)
|
42
|
+
return match.group(1).strip() if match else None
|
@@ -0,0 +1,65 @@
|
|
1
|
+
from typing import override
|
2
|
+
|
3
|
+
from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
|
4
|
+
from notionary.blocks.schemas import BlockColor, CreateQuoteBlock, CreateQuoteData
|
5
|
+
from notionary.page.content.parser.parsers.base import (
|
6
|
+
BlockParsingContext,
|
7
|
+
LineParser,
|
8
|
+
)
|
9
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
10
|
+
|
11
|
+
|
12
|
+
class QuoteParser(LineParser):
|
13
|
+
def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
|
14
|
+
super().__init__(syntax_registry)
|
15
|
+
self._syntax = syntax_registry.get_quote_syntax()
|
16
|
+
self._rich_text_converter = rich_text_converter
|
17
|
+
|
18
|
+
@override
|
19
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
20
|
+
if context.is_inside_parent_context():
|
21
|
+
return False
|
22
|
+
return self._is_quote(context.line)
|
23
|
+
|
24
|
+
@override
|
25
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
26
|
+
quote_lines = self._collect_quote_lines(context)
|
27
|
+
lines_consumed = len(quote_lines)
|
28
|
+
|
29
|
+
block = await self._create_quote_block(quote_lines)
|
30
|
+
if block:
|
31
|
+
context.result_blocks.append(block)
|
32
|
+
context.lines_consumed = lines_consumed
|
33
|
+
|
34
|
+
def _collect_quote_lines(self, context: BlockParsingContext) -> list[str]:
|
35
|
+
quote_lines = [context.line]
|
36
|
+
for line in context.get_remaining_lines():
|
37
|
+
if not self._is_quote(line):
|
38
|
+
break
|
39
|
+
quote_lines.append(line)
|
40
|
+
return quote_lines
|
41
|
+
|
42
|
+
def _is_quote(self, line: str) -> bool:
|
43
|
+
return self._syntax.regex_pattern.match(line) is not None
|
44
|
+
|
45
|
+
async def _create_quote_block(self, quote_lines: list[str]) -> CreateQuoteBlock | None:
|
46
|
+
if not quote_lines:
|
47
|
+
return None
|
48
|
+
|
49
|
+
contents = []
|
50
|
+
for line in quote_lines:
|
51
|
+
match = self._syntax.regex_pattern.match(line)
|
52
|
+
if match:
|
53
|
+
contents.append(match.group(1).strip())
|
54
|
+
|
55
|
+
if not contents:
|
56
|
+
return None
|
57
|
+
|
58
|
+
content = self._join_contents_for_multiline_quote(contents)
|
59
|
+
|
60
|
+
rich_text = await self._rich_text_converter.to_rich_text(content)
|
61
|
+
quote_data = CreateQuoteData(rich_text=rich_text, color=BlockColor.DEFAULT)
|
62
|
+
return CreateQuoteBlock(quote=quote_data)
|
63
|
+
|
64
|
+
def _join_contents_for_multiline_quote(self, contents: list[str]) -> str:
|
65
|
+
return "\n".join(contents)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
from typing import override
|
2
|
+
|
3
|
+
from notionary.blocks.schemas import BlockColor, CreateParagraphBlock, ParagraphData
|
4
|
+
from notionary.page.content.parser.parsers.base import (
|
5
|
+
BlockParsingContext,
|
6
|
+
LineParser,
|
7
|
+
)
|
8
|
+
from notionary.page.content.syntax.service import SyntaxRegistry
|
9
|
+
|
10
|
+
|
11
|
+
class SpaceParser(LineParser):
|
12
|
+
"""
|
13
|
+
Parser for [space] markers that create empty paragraph blocks.
|
14
|
+
Uses SyntaxRegistry for centralized syntax definition.
|
15
|
+
"""
|
16
|
+
|
17
|
+
def __init__(self, syntax_registry: SyntaxRegistry) -> None:
|
18
|
+
super().__init__(syntax_registry)
|
19
|
+
self._syntax = syntax_registry.get_space_syntax()
|
20
|
+
|
21
|
+
@override
|
22
|
+
def _can_handle(self, context: BlockParsingContext) -> bool:
|
23
|
+
if context.is_inside_parent_context():
|
24
|
+
return False
|
25
|
+
return self._syntax.regex_pattern.match(context.line.strip()) is not None
|
26
|
+
|
27
|
+
@override
|
28
|
+
async def _process(self, context: BlockParsingContext) -> None:
|
29
|
+
block = self._create_space_block()
|
30
|
+
if block:
|
31
|
+
context.result_blocks.append(block)
|
32
|
+
|
33
|
+
def _create_space_block(self) -> CreateParagraphBlock:
|
34
|
+
paragraph_data = ParagraphData(rich_text=[], color=BlockColor.DEFAULT)
|
35
|
+
return CreateParagraphBlock(paragraph=paragraph_data)
|