@ecsplico/editor 3.5.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +71 -0
- package/dist/adapters/direct-ai.d.ts +4 -4
- package/dist/adapters/direct-ai.js +2 -2
- package/dist/adapters/direct-ai.js.map +1 -1
- package/dist/adapters/document-state.d.ts +1 -1
- package/dist/adapters/document-state.js.map +1 -1
- package/dist/adapters/forge.d.ts +2 -2
- package/dist/adapters/forge.js.map +1 -1
- package/dist/adapters/nitro.d.ts +11 -3
- package/dist/adapters/nitro.js +3 -1
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +6 -6
- package/dist/adapters/shared.js.map +1 -1
- package/dist/code/CodeSurface.vue.d.ts +3 -3
- package/dist/config/index.d.ts +14 -14
- package/dist/config/index.js +8 -8
- package/dist/config/index.js.map +1 -1
- package/dist/core/backend-types.d.ts +3 -3
- package/dist/core/backend-types.js.map +1 -1
- package/dist/core/backend.d.ts +4 -4
- package/dist/core/backend.js.map +1 -1
- package/dist/core/block-convert.d.ts +1 -1
- package/dist/core/block-convert.js +5 -5
- package/dist/core/block-convert.js.map +1 -1
- package/dist/core/block-transfer.d.ts +8 -4
- package/dist/core/block-transfer.js +23 -14
- package/dist/core/block-transfer.js.map +1 -1
- package/dist/core/capabilities.d.ts +113 -0
- package/dist/core/capabilities.js +155 -0
- package/dist/core/capabilities.js.map +1 -0
- package/dist/core/command-types.d.ts +1 -1
- package/dist/core/context.js.map +1 -1
- package/dist/core/convert.d.ts +5 -5
- package/dist/core/convert.js +5 -5
- package/dist/core/convert.js.map +1 -1
- package/dist/core/core-feature.js +1 -1
- package/dist/core/define-editor.d.ts +2 -2
- package/dist/core/define-editor.js +34 -6
- package/dist/core/define-editor.js.map +1 -1
- package/dist/core/derivation.d.ts +119 -0
- package/dist/core/derivation.js +187 -0
- package/dist/core/derivation.js.map +1 -0
- package/dist/core/derive.d.ts +61 -0
- package/dist/core/derive.js +69 -0
- package/dist/core/derive.js.map +1 -0
- package/dist/core/extension-points.d.ts +16 -0
- package/dist/core/feature-context.d.ts +5 -1
- package/dist/core/feature-context.js +10 -3
- package/dist/core/feature-context.js.map +1 -1
- package/dist/core/feature.d.ts +41 -19
- package/dist/core/feature.js.map +1 -1
- package/dist/core/fences.js +1 -1
- package/dist/core/fences.js.map +1 -1
- package/dist/core/index.d.ts +6 -2
- package/dist/core/index.js +5 -1
- package/dist/core/pipeline.d.ts +14 -5
- package/dist/core/pipeline.js +19 -7
- package/dist/core/pipeline.js.map +1 -1
- package/dist/core/properties.d.ts +22 -0
- package/dist/core/properties.js +17 -0
- package/dist/core/properties.js.map +1 -0
- package/dist/core/schema/block-ids.js +5 -5
- package/dist/core/schema/block-ids.js.map +1 -1
- package/dist/core/schema/index.d.ts +2 -1
- package/dist/core/schema/index.js +2 -1
- package/dist/core/schema/index.js.map +1 -1
- package/dist/core/schema/opaque-fence.d.ts +4 -4
- package/dist/core/schema/opaque-fence.js +7 -7
- package/dist/core/schema/opaque-fence.js.map +1 -1
- package/dist/core/schema/persisted-names.d.ts +58 -0
- package/dist/core/schema/persisted-names.js +96 -0
- package/dist/core/schema/persisted-names.js.map +1 -0
- package/dist/core/toolbar-items.js +1 -1
- package/dist/core/toolbar-items.js.map +1 -1
- package/dist/core/util.js +5 -1
- package/dist/core/util.js.map +1 -1
- package/dist/document/DocumentSurface.vue.d.ts +3 -3
- package/dist/features/ai/agent-ops.js +1 -1
- package/dist/features/ai/ai-review.js +1 -1
- package/dist/features/ai/assistant.d.ts +4 -4
- package/dist/features/ai/assistant.js +1 -1
- package/dist/features/ai/assistant.js.map +1 -1
- package/dist/features/ai/components/AiSelectionMenu.js +1 -1
- package/dist/features/ai/components/AiSelectionMenu.js.map +1 -1
- package/dist/features/ai/components/ModelQuickSwitch.js +7 -7
- package/dist/features/ai/components/ModelQuickSwitch.js.map +1 -1
- package/dist/features/ai/components/ModelQuickSwitch.vue.d.ts +4 -4
- package/dist/features/ai/components/SettingsAiTab.js +8 -8
- package/dist/features/ai/components/SettingsAiTab.js.map +1 -1
- package/dist/features/ai/components/SettingsModelProfiles.js +1 -1
- package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/document-chat-model.d.ts +2 -2
- package/dist/features/ai/document-chat-model.js +5 -5
- package/dist/features/ai/document-chat-model.js.map +1 -1
- package/dist/features/ai/document-chat.js +2 -2
- package/dist/features/ai/document-chat.js.map +1 -1
- package/dist/features/ai/feature.d.ts +2 -2
- package/dist/features/ai/feature.js +2 -2
- package/dist/features/ai/feature.js.map +1 -1
- package/dist/features/ai/ghost-autocomplete.d.ts +4 -4
- package/dist/features/ai/ghost-autocomplete.js +1 -1
- package/dist/features/ai/ghost-autocomplete.js.map +1 -1
- package/dist/features/ai/index.d.ts +3 -3
- package/dist/features/ai/index.js +2 -2
- package/dist/features/ai/model-profiles.d.ts +9 -9
- package/dist/features/ai/model-profiles.js +13 -13
- package/dist/features/ai/model-profiles.js.map +1 -1
- package/dist/features/ai/protocol/agent-ops.d.ts +2 -2
- package/dist/features/ai/protocol/agent-ops.js +1 -1
- package/dist/features/ai/protocol/agent-ops.js.map +1 -1
- package/dist/features/ai/protocol/block-lines.d.ts +7 -7
- package/dist/features/ai/protocol/block-lines.js +10 -10
- package/dist/features/ai/protocol/block-lines.js.map +1 -1
- package/dist/features/ai/protocol/chat.d.ts +5 -5
- package/dist/features/ai/protocol/chat.js +12 -12
- package/dist/features/ai/protocol/chat.js.map +1 -1
- package/dist/features/ai/protocol/generate.d.ts +1 -1
- package/dist/features/ai/protocol/generate.js +1 -1
- package/dist/features/ai/protocol/generate.js.map +1 -1
- package/dist/features/ai/protocol/index.d.ts +3 -3
- package/dist/features/ai/protocol/index.js +2 -2
- package/dist/features/ai/protocol/models.d.ts +3 -3
- package/dist/features/ai/protocol/models.js +3 -3
- package/dist/features/ai/protocol/models.js.map +1 -1
- package/dist/features/ai/protocol/schemas.d.ts +1 -1
- package/dist/features/ai/protocol/schemas.js +1 -1
- package/dist/features/ai/protocol/schemas.js.map +1 -1
- package/dist/features/ai/protocol/tasks.d.ts +5 -5
- package/dist/features/ai/protocol/tasks.js +12 -12
- package/dist/features/ai/protocol/tasks.js.map +1 -1
- package/dist/features/ai/react/AiSelectionMenu.js.map +1 -1
- package/dist/features/ai/react/ModelQuickSwitch.d.ts +4 -4
- package/dist/features/ai/react/ModelQuickSwitch.js +6 -6
- package/dist/features/ai/react/ModelQuickSwitch.js.map +1 -1
- package/dist/features/ai/react/SettingsAiTab.d.ts +1 -1
- package/dist/features/ai/react/SettingsAiTab.js +8 -8
- package/dist/features/ai/react/SettingsAiTab.js.map +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.d.ts +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.js +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/react/use-ai-assistant.js +1 -1
- package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/react/use-model-profiles.d.ts +5 -5
- package/dist/features/ai/react/use-model-profiles.js +2 -2
- package/dist/features/ai/react/use-model-profiles.js.map +1 -1
- package/dist/features/ai/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/use-ai-assistant.js +1 -1
- package/dist/features/ai/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/use-model-profiles.d.ts +4 -4
- package/dist/features/ai/use-model-profiles.js +2 -2
- package/dist/features/ai/use-model-profiles.js.map +1 -1
- package/dist/features/block-ui/block-actions.d.ts +8 -4
- package/dist/features/block-ui/block-actions.js +38 -22
- package/dist/features/block-ui/block-actions.js.map +1 -1
- package/dist/features/block-ui/block-target.d.ts +29 -0
- package/dist/features/block-ui/block-target.js +63 -0
- package/dist/features/block-ui/block-target.js.map +1 -0
- package/dist/features/block-ui/components/BlockHandles.js +3 -3
- package/dist/features/block-ui/components/BlockHandles.js.map +1 -1
- package/dist/features/block-ui/components/BlockUi.js +11 -23
- package/dist/features/block-ui/components/BlockUi.js.map +1 -1
- package/dist/features/block-ui/feature.d.ts +3 -2
- package/dist/features/block-ui/feature.js +3 -2
- package/dist/features/block-ui/feature.js.map +1 -1
- package/dist/features/block-ui/handle-geometry.js +12 -23
- package/dist/features/block-ui/handle-geometry.js.map +1 -1
- package/dist/features/block-ui/index.d.ts +2 -1
- package/dist/features/block-ui/index.js +2 -1
- package/dist/features/block-ui/react/BlockHandles.d.ts +1 -1
- package/dist/features/block-ui/react/BlockHandles.js +4 -4
- package/dist/features/block-ui/react/BlockHandles.js.map +1 -1
- package/dist/features/block-ui/react/BlockUi.js +13 -25
- package/dist/features/block-ui/react/BlockUi.js.map +1 -1
- package/dist/features/comments/model.js +1 -1
- package/dist/features/composites/accepted-children.d.ts +5 -4
- package/dist/features/composites/accepted-children.js +26 -26
- package/dist/features/composites/accepted-children.js.map +1 -1
- package/dist/features/composites/ai-brief.d.ts +4 -4
- package/dist/features/composites/ai-brief.js +14 -12
- package/dist/features/composites/ai-brief.js.map +1 -1
- package/dist/features/composites/anchors.d.ts +1 -1
- package/dist/features/composites/anchors.js.map +1 -1
- package/dist/features/composites/baskets.d.ts +1 -1
- package/dist/features/composites/baskets.js.map +1 -1
- package/dist/features/composites/bibliography-command.d.ts +1 -1
- package/dist/features/composites/bibliography-form.js +1 -1
- package/dist/features/composites/bibliography-form.js.map +1 -1
- package/dist/features/composites/bibliography.js.map +1 -1
- package/dist/features/composites/block-types-json.d.ts +38 -0
- package/dist/features/composites/block-types-json.js +122 -0
- package/dist/features/composites/block-types-json.js.map +1 -0
- package/dist/features/composites/block-types.d.ts +119 -0
- package/dist/features/composites/block-types.js +343 -0
- package/dist/features/composites/block-types.js.map +1 -0
- package/dist/features/composites/capabilities.js +109 -0
- package/dist/features/composites/capabilities.js.map +1 -0
- package/dist/features/composites/components/BibliographyEditor.js +5 -5
- package/dist/features/composites/components/BibliographyEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeBasketMenu.js +2 -2
- package/dist/features/composites/components/CompositeBasketMenu.js.map +1 -1
- package/dist/features/composites/components/CompositeChrome.js +18 -8
- package/dist/features/composites/components/CompositeChrome.js.map +1 -1
- package/dist/features/composites/components/CompositeChrome.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeDetails.js +11 -10
- package/dist/features/composites/components/CompositeDetails.js.map +1 -1
- package/dist/features/composites/components/CompositeDetails.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeFieldEditor.js +7 -7
- package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeFieldEditor.vue.d.ts +5 -5
- package/dist/features/composites/components/CompositeInspector.js +136 -113
- package/dist/features/composites/components/CompositeInspector.js.map +1 -1
- package/dist/features/composites/components/CompositeInspector.vue.d.ts +3 -3
- package/dist/features/composites/components/CompositeStatusMenu.js +2 -2
- package/dist/features/composites/components/CompositeStatusMenu.js.map +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.js +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeTable.js +2 -2
- package/dist/features/composites/components/CompositeTable.js.map +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeView.js +19 -17
- package/dist/features/composites/components/CompositeView.js.map +1 -1
- package/dist/features/composites/components/DerivationBadge.js +15 -6
- package/dist/features/composites/components/DerivationBadge.js.map +1 -1
- package/dist/features/composites/components/FocusChip.js +1 -1
- package/dist/features/composites/components/FocusChip.js.map +1 -1
- package/dist/features/composites/components/FocusChip.vue.d.ts +1 -1
- package/dist/features/composites/components/ReferenceFieldSelect.js +3 -3
- package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -1
- package/dist/features/composites/components/ReferenceView.js +1 -1
- package/dist/features/composites/components/ReferenceView.js.map +1 -1
- package/dist/features/composites/components/SettingsEditingTab.js +18 -18
- package/dist/features/composites/components/SettingsEditingTab.js.map +1 -1
- package/dist/features/composites/components/SettingsEditingTab.vue.d.ts +3 -3
- package/dist/features/composites/convert.d.ts +4 -4
- package/dist/features/composites/convert.js +27 -28
- package/dist/features/composites/convert.js.map +1 -1
- package/dist/features/composites/derived-chrome.js +34 -28
- package/dist/features/composites/derived-chrome.js.map +1 -1
- package/dist/features/composites/editing-settings-keys.js +6 -6
- package/dist/features/composites/editing-settings-keys.js.map +1 -1
- package/dist/features/composites/feature.d.ts +10 -10
- package/dist/features/composites/feature.js +58 -46
- package/dist/features/composites/feature.js.map +1 -1
- package/dist/features/composites/fences.d.ts +3 -3
- package/dist/features/composites/fences.js +18 -13
- package/dist/features/composites/fences.js.map +1 -1
- package/dist/features/composites/focus.d.ts +10 -10
- package/dist/features/composites/focus.js +11 -11
- package/dist/features/composites/focus.js.map +1 -1
- package/dist/features/composites/heading-composites.d.ts +5 -5
- package/dist/features/composites/heading-composites.js +13 -16
- package/dist/features/composites/heading-composites.js.map +1 -1
- package/dist/features/composites/index.d.ts +20 -18
- package/dist/features/composites/index.js +9 -7
- package/dist/features/composites/inspector-model.d.ts +45 -22
- package/dist/features/composites/inspector-model.js +53 -14
- package/dist/features/composites/inspector-model.js.map +1 -1
- package/dist/features/composites/legacy.d.ts +5 -4
- package/dist/features/composites/legacy.js +16 -23
- package/dist/features/composites/legacy.js.map +1 -1
- package/dist/features/composites/markdown-export.js +3 -3
- package/dist/features/composites/markdown-export.js.map +1 -1
- package/dist/features/composites/merge.d.ts +8 -7
- package/dist/features/composites/merge.js +39 -12
- package/dist/features/composites/merge.js.map +1 -1
- package/dist/features/composites/meta-display.js +5 -5
- package/dist/features/composites/meta-display.js.map +1 -1
- package/dist/features/composites/meta-keys.d.ts +5 -5
- package/dist/features/composites/meta-keys.js +8 -8
- package/dist/features/composites/meta-keys.js.map +1 -1
- package/dist/features/composites/node-views.d.ts +3 -3
- package/dist/features/composites/node-views.js +2 -2
- package/dist/features/composites/node-views.js.map +1 -1
- package/dist/features/composites/nodes.d.ts +13 -13
- package/dist/features/composites/nodes.js +100 -77
- package/dist/features/composites/nodes.js.map +1 -1
- package/dist/features/composites/outline.d.ts +15 -12
- package/dist/features/composites/outline.js +24 -21
- package/dist/features/composites/outline.js.map +1 -1
- package/dist/features/composites/properties.d.ts +51 -0
- package/dist/features/composites/properties.js +89 -0
- package/dist/features/composites/properties.js.map +1 -0
- package/dist/features/composites/react/BibliographyEditor.js +5 -5
- package/dist/features/composites/react/BibliographyEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeBasketMenu.js +2 -2
- package/dist/features/composites/react/CompositeBasketMenu.js.map +1 -1
- package/dist/features/composites/react/CompositeChrome.d.ts +1 -1
- package/dist/features/composites/react/CompositeChrome.js +15 -6
- package/dist/features/composites/react/CompositeChrome.js.map +1 -1
- package/dist/features/composites/react/CompositeDetails.d.ts +1 -1
- package/dist/features/composites/react/CompositeDetails.js +11 -10
- package/dist/features/composites/react/CompositeDetails.js.map +1 -1
- package/dist/features/composites/react/CompositeFieldEditor.d.ts +5 -5
- package/dist/features/composites/react/CompositeFieldEditor.js +6 -6
- package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeInspector.d.ts +3 -3
- package/dist/features/composites/react/CompositeInspector.js +142 -128
- package/dist/features/composites/react/CompositeInspector.js.map +1 -1
- package/dist/features/composites/react/CompositeStatusMenu.js +2 -2
- package/dist/features/composites/react/CompositeStatusMenu.js.map +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.d.ts +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeTable.d.ts +1 -1
- package/dist/features/composites/react/CompositeTable.js +3 -3
- package/dist/features/composites/react/CompositeTable.js.map +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.d.ts +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.js +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeView.js +17 -15
- package/dist/features/composites/react/CompositeView.js.map +1 -1
- package/dist/features/composites/react/DerivationBadge.js +13 -4
- package/dist/features/composites/react/DerivationBadge.js.map +1 -1
- package/dist/features/composites/react/FocusChip.d.ts +1 -1
- package/dist/features/composites/react/FocusChip.js +1 -1
- package/dist/features/composites/react/FocusChip.js.map +1 -1
- package/dist/features/composites/react/ReferenceFieldSelect.js +3 -3
- package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -1
- package/dist/features/composites/react/ReferenceView.d.ts +1 -1
- package/dist/features/composites/react/ReferenceView.js +1 -1
- package/dist/features/composites/react/ReferenceView.js.map +1 -1
- package/dist/features/composites/react/SettingsEditingTab.d.ts +4 -4
- package/dist/features/composites/react/SettingsEditingTab.js +20 -20
- package/dist/features/composites/react/SettingsEditingTab.js.map +1 -1
- package/dist/features/composites/react.js +1 -1
- package/dist/features/composites/react.js.map +1 -1
- package/dist/features/composites/reference-ai.js +1 -1
- package/dist/features/composites/reference-ai.js.map +1 -1
- package/dist/features/composites/reference-label.d.ts +3 -3
- package/dist/features/composites/reference-label.js +6 -6
- package/dist/features/composites/reference-label.js.map +1 -1
- package/dist/features/composites/reference-suggestion.d.ts +1 -1
- package/dist/features/composites/reference-suggestion.js +3 -3
- package/dist/features/composites/reference-suggestion.js.map +1 -1
- package/dist/features/composites/reference-text.d.ts +2 -2
- package/dist/features/composites/reference-text.js +4 -4
- package/dist/features/composites/reference-text.js.map +1 -1
- package/dist/features/composites/reference.d.ts +3 -3
- package/dist/features/composites/reference.js +1 -1
- package/dist/features/composites/reference.js.map +1 -1
- package/dist/features/composites/reveal-source.d.ts +3 -3
- package/dist/features/composites/reveal-source.js +6 -6
- package/dist/features/composites/reveal-source.js.map +1 -1
- package/dist/features/composites/rows-model.d.ts +2 -2
- package/dist/features/composites/rows-model.js +4 -3
- package/dist/features/composites/rows-model.js.map +1 -1
- package/dist/features/composites/rows.d.ts +16 -28
- package/dist/features/composites/rows.js +20 -54
- package/dist/features/composites/rows.js.map +1 -1
- package/dist/features/composites/schema.d.ts +12 -11
- package/dist/features/composites/schema.js +10 -9
- package/dist/features/composites/schema.js.map +1 -1
- package/dist/features/composites/source.d.ts +20 -0
- package/dist/features/composites/source.js +40 -0
- package/dist/features/composites/source.js.map +1 -0
- package/dist/features/composites/split.d.ts +11 -11
- package/dist/features/composites/split.js +20 -20
- package/dist/features/composites/split.js.map +1 -1
- package/dist/features/composites/structure-mode.js +3 -3
- package/dist/features/composites/structure-mode.js.map +1 -1
- package/dist/features/composites/table-model.js +2 -2
- package/dist/features/composites/table-model.js.map +1 -1
- package/dist/features/composites/use-composite-inspector.js +3 -1
- package/dist/features/composites/use-composite-inspector.js.map +1 -1
- package/dist/features/composites/use-composite-rows.d.ts +2 -2
- package/dist/features/composites/use-composite-rows.js.map +1 -1
- package/dist/features/composites/vue.js +1 -1
- package/dist/features/composites/vue.js.map +1 -1
- package/dist/features/image-studio/components/ImageStudioDialog.js +1 -1
- package/dist/features/image-studio/components/ImageStudioDialog.js.map +1 -1
- package/dist/features/image-studio/components/ImageStudioDialog.vue.d.ts +1 -1
- package/dist/features/image-studio/components/ImageStudioView.js.map +1 -1
- package/dist/features/image-studio/feature.d.ts +1 -1
- package/dist/features/image-studio/feature.js +1 -1
- package/dist/features/image-studio/feature.js.map +1 -1
- package/dist/features/image-studio/node-core.d.ts +3 -3
- package/dist/features/image-studio/node-core.js +1 -1
- package/dist/features/image-studio/node-core.js.map +1 -1
- package/dist/features/image-studio/node-store.d.ts +1 -1
- package/dist/features/image-studio/node-store.js +1 -1
- package/dist/features/image-studio/node-store.js.map +1 -1
- package/dist/features/image-studio/react/ImageStudioDialog.d.ts +1 -1
- package/dist/features/image-studio/react/ImageStudioDialog.js +1 -1
- package/dist/features/image-studio/react/ImageStudioDialog.js.map +1 -1
- package/dist/features/image-studio/react/ImageStudioView.js +1 -1
- package/dist/features/image-studio/react/ImageStudioView.js.map +1 -1
- package/dist/features/image-studio/react/store.d.ts +3 -3
- package/dist/features/image-studio/react/store.js.map +1 -1
- package/dist/features/image-studio/react.d.ts +1 -1
- package/dist/features/image-studio/react.js +1 -1
- package/dist/features/image-studio/react.js.map +1 -1
- package/dist/features/image-studio/schema.d.ts +1 -1
- package/dist/features/image-studio/schema.js +1 -1
- package/dist/features/image-studio/schema.js.map +1 -1
- package/dist/features/image-studio/state.d.ts +3 -3
- package/dist/features/image-studio/state.js +2 -2
- package/dist/features/image-studio/state.js.map +1 -1
- package/dist/features/image-studio/store.d.ts +3 -3
- package/dist/features/image-studio/vue.d.ts +1 -1
- package/dist/features/image-studio/vue.js +1 -1
- package/dist/features/image-studio/vue.js.map +1 -1
- package/dist/features/media/index.js +1 -1
- package/dist/features/media/react/AudioRecorderModal.js +1 -1
- package/dist/features/media/react.js +1 -1
- package/dist/features/mentions/tag.js +2 -1
- package/dist/features/mentions/tag.js.map +1 -1
- package/dist/features/themes/components/SettingsAppearanceTab.js +1 -1
- package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/feature.d.ts +1 -1
- package/dist/features/themes/feature.js.map +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.d.ts +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.js +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/theme-runtime.js +1 -1
- package/dist/features/themes/theme-runtime.js.map +1 -1
- package/dist/features/transcript/TranscriptSegmentView.js +1 -1
- package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/react/TranscriptSegmentView.js +1 -1
- package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/segment-node.js.map +1 -1
- package/dist/features/transfer/feature.js +1 -1
- package/dist/features/transfer/feature.js.map +1 -1
- package/dist/features/transfer/transforms.d.ts +4 -4
- package/dist/features/transfer/transforms.js +12 -12
- package/dist/features/transfer/transforms.js.map +1 -1
- package/dist/i18n/de/ai.js +4 -4
- package/dist/i18n/de/ai.js.map +1 -1
- package/dist/i18n/de/authors.js +1 -1
- package/dist/i18n/de/authors.js.map +1 -1
- package/dist/i18n/de/comments.js +1 -1
- package/dist/i18n/de/comments.js.map +1 -1
- package/dist/i18n/de/composites.js +62 -59
- package/dist/i18n/de/composites.js.map +1 -1
- package/dist/i18n/de/image-studio.js +2 -2
- package/dist/i18n/de/image-studio.js.map +1 -1
- package/dist/i18n/de/integrations.js +20 -20
- package/dist/i18n/de/integrations.js.map +1 -1
- package/dist/i18n/de/markdown.js +1 -1
- package/dist/i18n/de/markdown.js.map +1 -1
- package/dist/i18n/de/palette.js +1 -1
- package/dist/i18n/de/palette.js.map +1 -1
- package/dist/i18n/de/themes.js +3 -3
- package/dist/i18n/de/themes.js.map +1 -1
- package/dist/i18n/de/transfer.js +2 -2
- package/dist/i18n/de/transfer.js.map +1 -1
- package/dist/i18n/de/tree.js +6 -6
- package/dist/i18n/de/tree.js.map +1 -1
- package/dist/i18n/de.d.ts +101 -98
- package/dist/i18n/en/ai.js +2 -2
- package/dist/i18n/en/ai.js.map +1 -1
- package/dist/i18n/en/composites.js +64 -61
- package/dist/i18n/en/composites.js.map +1 -1
- package/dist/i18n/en/integrations.js +9 -9
- package/dist/i18n/en/integrations.js.map +1 -1
- package/dist/i18n/en/markdown.js +1 -1
- package/dist/i18n/en/markdown.js.map +1 -1
- package/dist/i18n/en/palette.js +1 -1
- package/dist/i18n/en/palette.js.map +1 -1
- package/dist/i18n/en/themes.js +4 -4
- package/dist/i18n/en/themes.js.map +1 -1
- package/dist/i18n/en/tree.js +5 -5
- package/dist/i18n/en/tree.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/integrations/composite-ai/bibliography-fetch.d.ts +6 -6
- package/dist/integrations/composite-ai/bibliography-fetch.js +19 -19
- package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -1
- package/dist/integrations/composite-ai/composite-fill.d.ts +4 -4
- package/dist/integrations/composite-ai/composite-fill.js +5 -5
- package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
- package/dist/integrations/composite-ai/composite-summary.d.ts +2 -2
- package/dist/integrations/composite-ai/composite-summary.js +5 -5
- package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
- package/dist/integrations/composite-ai/derive.d.ts +17 -17
- package/dist/integrations/composite-ai/derive.js +27 -26
- package/dist/integrations/composite-ai/derive.js.map +1 -1
- package/dist/integrations/composite-ai/index.d.ts +14 -15
- package/dist/integrations/composite-ai/index.js +98 -77
- package/dist/integrations/composite-ai/index.js.map +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.d.ts +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.js +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.js.map +1 -1
- package/dist/integrations/composite-ai/rendition.d.ts +9 -9
- package/dist/integrations/composite-ai/rendition.js +27 -27
- package/dist/integrations/composite-ai/rendition.js.map +1 -1
- package/dist/integrations/composite-ai/split.d.ts +8 -8
- package/dist/integrations/composite-ai/split.js +12 -12
- package/dist/integrations/composite-ai/split.js.map +1 -1
- package/dist/integrations/composite-ai/transfer-transforms.d.ts +2 -2
- package/dist/integrations/composite-ai/transfer-transforms.js +12 -12
- package/dist/integrations/composite-ai/transfer-transforms.js.map +1 -1
- package/dist/integrations/composite-media/index.d.ts +4 -3
- package/dist/integrations/composite-media/index.js +20 -14
- package/dist/integrations/composite-media/index.js.map +1 -1
- package/dist/markdown/MarkdownSurface.vue.d.ts +7 -7
- package/dist/markdown/document.js +1 -1
- package/dist/markdown/document.js.map +1 -1
- package/dist/nuxt/module.d.ts +30 -24
- package/dist/nuxt/module.js.map +1 -1
- package/dist/nuxt/runtime/server/plugins/editor-server.js +3 -2
- package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
- package/dist/presets/compose.d.ts +6 -6
- package/dist/presets/compose.js +8 -5
- package/dist/presets/compose.js.map +1 -1
- package/dist/react/AdvancedEditor.d.ts +2 -2
- package/dist/react/AdvancedEditor.js +1 -1
- package/dist/react/AdvancedEditor.js.map +1 -1
- package/dist/react/compose.d.ts +1 -1
- package/dist/react/compose.js +2 -2
- package/dist/react/compose.js.map +1 -1
- package/dist/react/composed-surface.d.ts +5 -5
- package/dist/react/composed-surface.js +2 -2
- package/dist/react/composed-surface.js.map +1 -1
- package/dist/server/ai.d.ts +7 -7
- package/dist/server/ai.js +1 -1
- package/dist/server/ai.js.map +1 -1
- package/dist/server/auth.d.ts +1 -1
- package/dist/server/collab-state.d.ts +1 -1
- package/dist/server/collab-state.js.map +1 -1
- package/dist/server/collab.d.ts +4 -4
- package/dist/server/collab.js +22 -17
- package/dist/server/collab.js.map +1 -1
- package/dist/server/handlers/ai.d.ts +9 -6
- package/dist/server/handlers/ai.js +13 -17
- package/dist/server/handlers/ai.js.map +1 -1
- package/dist/server/handlers/context.d.ts +4 -0
- package/dist/server/handlers/context.js.map +1 -1
- package/dist/server/handlers/editor.d.ts +33 -32
- package/dist/server/handlers/editor.js +13 -8
- package/dist/server/handlers/editor.js.map +1 -1
- package/dist/server/handlers/images.d.ts +1 -1
- package/dist/server/handlers/images.js +1 -1
- package/dist/server/handlers/images.js.map +1 -1
- package/dist/server/host.d.ts +4 -0
- package/dist/server/host.js +10 -2
- package/dist/server/host.js.map +1 -1
- package/dist/server/index.d.ts +3 -3
- package/dist/server/ports.d.ts +8 -8
- package/dist/server/ports.js.map +1 -1
- package/dist/settings/index.d.ts +20 -19
- package/dist/settings/index.js +25 -24
- package/dist/settings/index.js.map +1 -1
- package/dist/settings/migrate.d.ts +18 -0
- package/dist/settings/migrate.js +46 -0
- package/dist/settings/migrate.js.map +1 -0
- package/dist/settings/values.d.ts +12 -12
- package/dist/settings/values.js +11 -11
- package/dist/settings/values.js.map +1 -1
- package/dist/styles/composites.css +10 -10
- package/dist/tree/DocumentTree.js +12 -5
- package/dist/tree/DocumentTree.js.map +1 -1
- package/dist/tree/drop-rules.js +5 -5
- package/dist/tree/drop-rules.js.map +1 -1
- package/dist/tree/react/DocumentTree.js +14 -5
- package/dist/tree/react/DocumentTree.js.map +1 -1
- package/dist/tree/tree-host.js +6 -6
- package/dist/tree/tree-host.js.map +1 -1
- package/dist/tree/tree-items.js +34 -28
- package/dist/tree/tree-items.js.map +1 -1
- package/dist/tree/tree-model.js +16 -16
- package/dist/tree/tree-model.js.map +1 -1
- package/dist/tree/tree-rows.js +2 -2
- package/dist/tree/tree-rows.js.map +1 -1
- package/dist/tree/tree-view-model.d.ts +2 -2
- package/dist/tree/tree-view-model.js.map +1 -1
- package/dist/vue/AdvancedEditor.js +2 -2
- package/dist/vue/AdvancedEditor.js.map +1 -1
- package/dist/vue/AdvancedEditor.vue.d.ts +10 -10
- package/dist/vue/SimpleEditor.vue.d.ts +4 -4
- package/dist/vue/components/EditorSurface.vue.d.ts +4 -4
- package/dist/vue/compose.d.ts +1 -1
- package/dist/vue/compose.js +2 -2
- package/dist/vue/compose.js.map +1 -1
- package/package.json +1 -1
- package/dist/features/composites/derivation.d.ts +0 -62
- package/dist/features/composites/derivation.js +0 -102
- package/dist/features/composites/derivation.js.map +0 -1
- package/dist/features/composites/kinds.d.ts +0 -83
- package/dist/features/composites/kinds.js +0 -285
- package/dist/features/composites/kinds.js.map +0 -1
|
@@ -1,15 +1,18 @@
|
|
|
1
|
+
import { fail as fail$1 } from "./util.js";
|
|
2
|
+
import { BUILT_IN_BLOCK_CAPABILITIES, createCapabilityRegistry } from "./capabilities.js";
|
|
3
|
+
import { createDeriveRegistry } from "./derive.js";
|
|
1
4
|
import { SINGLETON_PIPELINE_HOOKS } from "./feature.js";
|
|
5
|
+
import { migratePersistedNames } from "./schema/persisted-names.js";
|
|
2
6
|
import { DEFAULT_BLOCK_PIPELINE } from "./pipeline.js";
|
|
3
|
-
import { fail as fail$1 } from "./util.js";
|
|
4
7
|
//#region src/core/define-editor.ts
|
|
5
8
|
const FEATURE_SINGLETONS = ["anchorResolver", "formatAiResult"];
|
|
6
9
|
const fail = (message) => fail$1(message, "defineEditor");
|
|
7
10
|
/**
|
|
8
11
|
* Validates `features` and resolves their pipeline and conversion providers. Keeps the given order; neither
|
|
9
12
|
* deduplicates nor installs missing dependencies. Throws on duplicate ids, a `requires` entry that is not installed,
|
|
10
|
-
* a toolbar group declared by two features (`toolbarGroups`) and a singleton hook (`parseMarkdown`, `segment`, `structure`, `wrapImport`, `migrateContent`, `anchorResolver`,
|
|
13
|
+
* a toolbar group declared by two features (`toolbarGroups`), a block capability declared twice or with a built-in id (`blockCapabilities`), a derive method declared twice, with neither `run` nor `menu` or requiring an undeclared capability (`deriveMethods`) and a singleton hook (`parseMarkdown`, `segment`, `structure`, `wrapImport`, `migrateContent`, `anchorResolver`,
|
|
11
14
|
* `formatAiResult`) contributed twice. A command naming a toolbar group no feature declares needs the feature context
|
|
12
|
-
* to build the commands: `toolbarOf` throws it. `normalize` hooks chain left to right. `aiContext` contributions merge (`
|
|
15
|
+
* to build the commands: `toolbarOf` throws it. `normalize` hooks chain left to right. `aiContext` contributions merge (`blockTypes` and `blocks`
|
|
13
16
|
* concatenated in feature order, `structure` from one feature only); their conflicts surface when the merged `aiContext` reads the editor.
|
|
14
17
|
* `aiBlockData` contributions are additive too: they run in parallel per block and their data concatenate in feature order.
|
|
15
18
|
*/
|
|
@@ -28,6 +31,24 @@ function defineEditor(config) {
|
|
|
28
31
|
if (owner) fail(`features "${owner}" and "${feature.id}" both declare toolbar group "${group.id}"`);
|
|
29
32
|
groups.set(group.id, feature.id);
|
|
30
33
|
}
|
|
34
|
+
const capabilities = [...BUILT_IN_BLOCK_CAPABILITIES];
|
|
35
|
+
const capabilityOwners = new Map(capabilities.map((capability) => [capability.id, "the editor core"]));
|
|
36
|
+
for (const feature of features) for (const capability of feature.blockCapabilities ?? []) {
|
|
37
|
+
const owner = capabilityOwners.get(capability.id);
|
|
38
|
+
if (owner) fail(`the block capability "${capability.id}" is declared by ${owner} and by feature "${feature.id}"`);
|
|
39
|
+
capabilityOwners.set(capability.id, `feature "${feature.id}"`);
|
|
40
|
+
capabilities.push(capability);
|
|
41
|
+
}
|
|
42
|
+
const deriveMethods = [];
|
|
43
|
+
const deriveOwners = /* @__PURE__ */ new Map();
|
|
44
|
+
for (const feature of features) for (const method of feature.deriveMethods ?? []) {
|
|
45
|
+
const owner = deriveOwners.get(method.id);
|
|
46
|
+
if (owner) fail(`the derive method "${method.id}" is declared by feature "${owner}" and by feature "${feature.id}"`);
|
|
47
|
+
deriveOwners.set(method.id, feature.id);
|
|
48
|
+
if (!method.run === !method.menu) fail(`the derive method "${method.id}" of feature "${feature.id}" needs exactly one of run and menu`);
|
|
49
|
+
for (const required of method.requires) if (!capabilityOwners.has(required)) fail(`the derive method "${method.id}" of feature "${feature.id}" requires the capability "${required}", which no feature declares`);
|
|
50
|
+
deriveMethods.push(method);
|
|
51
|
+
}
|
|
31
52
|
const owners = /* @__PURE__ */ new Map();
|
|
32
53
|
const claim = (hook, feature) => {
|
|
33
54
|
const owner = owners.get(hook);
|
|
@@ -49,6 +70,8 @@ function defineEditor(config) {
|
|
|
49
70
|
}
|
|
50
71
|
}
|
|
51
72
|
if (normalizers.length) pipeline.normalize = (editor, blocks) => normalizers.reduce((current, normalize) => normalize(editor, current), blocks);
|
|
73
|
+
const contributed = pipeline.migrateContent;
|
|
74
|
+
if (contributed !== DEFAULT_BLOCK_PIPELINE.migrateContent) pipeline.migrateContent = (content) => contributed(migratePersistedNames(content));
|
|
52
75
|
const conversions = features.flatMap((feature) => [...feature.conversions ?? []]);
|
|
53
76
|
const contexts = features.flatMap((feature) => feature.aiContext ? [{
|
|
54
77
|
id: feature.id,
|
|
@@ -56,13 +79,13 @@ function defineEditor(config) {
|
|
|
56
79
|
}] : []);
|
|
57
80
|
const aiContext = contexts.length ? (editor) => {
|
|
58
81
|
const merged = {
|
|
59
|
-
|
|
82
|
+
blockTypes: [],
|
|
60
83
|
blocks: []
|
|
61
84
|
};
|
|
62
85
|
const blockIds = /* @__PURE__ */ new Set();
|
|
63
86
|
for (const { id, read } of contexts) {
|
|
64
87
|
const context = read(editor);
|
|
65
|
-
merged.
|
|
88
|
+
merged.blockTypes.push(...context.blockTypes ?? []);
|
|
66
89
|
for (const block of context.blocks ?? []) {
|
|
67
90
|
if (blockIds.has(block.id)) fail(`the AI block "${block.id}" is described by more than one feature`);
|
|
68
91
|
blockIds.add(block.id);
|
|
@@ -74,7 +97,7 @@ function defineEditor(config) {
|
|
|
74
97
|
merged.structure = context.structure;
|
|
75
98
|
}
|
|
76
99
|
return {
|
|
77
|
-
|
|
100
|
+
blockTypes: merged.blockTypes,
|
|
78
101
|
blocks: merged.blocks,
|
|
79
102
|
...merged.structure && { structure: merged.structure }
|
|
80
103
|
};
|
|
@@ -82,10 +105,15 @@ function defineEditor(config) {
|
|
|
82
105
|
const dataProviders = features.flatMap((feature) => feature.aiBlockData ? [feature.aiBlockData] : []);
|
|
83
106
|
const aiBlockData = dataProviders.length ? async (request) => (await Promise.all(dataProviders.map((provide) => provide(request)))).flat() : void 0;
|
|
84
107
|
const formatAiResult = features.find((feature) => feature.formatAiResult)?.formatAiResult;
|
|
108
|
+
const blockTypeSources = features.flatMap((feature) => feature.blockTypes ? [feature.blockTypes] : []);
|
|
109
|
+
const blockTypes = blockTypeSources.length ? (editor) => blockTypeSources.length === 1 ? blockTypeSources[0](editor) : blockTypeSources.flatMap((source) => [...source(editor)]) : void 0;
|
|
85
110
|
return Object.freeze({
|
|
86
111
|
features,
|
|
87
112
|
pipeline: Object.freeze(pipeline),
|
|
88
113
|
conversions: Object.freeze(conversions),
|
|
114
|
+
capabilities: createCapabilityRegistry(Object.freeze(capabilities)),
|
|
115
|
+
deriveMethods: createDeriveRegistry(Object.freeze(deriveMethods)),
|
|
116
|
+
...blockTypes && { blockTypes },
|
|
89
117
|
...aiContext && { aiContext },
|
|
90
118
|
...aiBlockData && { aiBlockData },
|
|
91
119
|
...formatAiResult && { formatAiResult }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-editor.js","names":["failWith"],"sources":["../../src/core/define-editor.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { EditorContext } from './context'\nimport { type AiBlock, type AiBlockDataProvider, type AiContext, type AiContextKind, type BlockPipeline, type ConversionProvider, type EditorFeature, type EditorPreset, type SettingsTab, SINGLETON_PIPELINE_HOOKS } from './feature'\nimport { DEFAULT_BLOCK_PIPELINE } from './pipeline'\nimport { fail as failWith } from './util'\n\nconst FEATURE_SINGLETONS = ['anchorResolver', 'formatAiResult'] as const satisfies readonly (keyof EditorFeature)[]\n\nconst fail = (message: string): never => failWith(message, 'defineEditor')\n\n/**\n * Validates `features` and resolves their pipeline and conversion providers. Keeps the given order; neither\n * deduplicates nor installs missing dependencies. Throws on duplicate ids, a `requires` entry that is not installed,\n * a toolbar group declared by two features (`toolbarGroups`) and a singleton hook (`parseMarkdown`, `segment`, `structure`, `wrapImport`, `migrateContent`, `anchorResolver`,\n * `formatAiResult`) contributed twice. A command naming a toolbar group no feature declares needs the feature context\n * to build the commands: `toolbarOf` throws it. `normalize` hooks chain left to right. `aiContext` contributions merge (`kinds` and `blocks`\n * concatenated in feature order, `structure` from one feature only); their conflicts surface when the merged `aiContext` reads the editor.\n * `aiBlockData` contributions are additive too: they run in parallel per block and their data concatenate in feature order.\n */\nexport function defineEditor<C = unknown>(config: { features: readonly EditorFeature<C>[] }): EditorPreset<C> {\n const features = Object.freeze([...config.features])\n const ids = new Set<string>()\n for (const feature of features) {\n if (!feature.dimension) fail(`feature \"${feature.id}\" declares no dimension`)\n }\n for (const feature of features) {\n if (ids.has(feature.id)) fail(`duplicate feature id \"${feature.id}\"`)\n ids.add(feature.id)\n }\n for (const feature of features) {\n for (const required of feature.requires ?? []) {\n if (!ids.has(required)) fail(`feature \"${feature.id}\" requires \"${required}\", which is not installed`)\n }\n }\n const groups = new Map<string, string>()\n for (const feature of features) {\n for (const group of feature.toolbarGroups ?? []) {\n const owner = groups.get(group.id)\n if (owner) fail(`features \"${owner}\" and \"${feature.id}\" both declare toolbar group \"${group.id}\"`)\n groups.set(group.id, feature.id)\n }\n }\n\n const owners = new Map<string, string>()\n const claim = (hook: string, feature: EditorFeature<C>) => {\n const owner = owners.get(hook)\n if (owner) fail(`features \"${owner}\" and \"${feature.id}\" both contribute the singleton hook \"${hook}\"`)\n owners.set(hook, feature.id)\n }\n const pipeline: BlockPipeline = { ...DEFAULT_BLOCK_PIPELINE }\n const normalizers: BlockPipeline['normalize'][] = []\n for (const feature of features) {\n for (const hook of FEATURE_SINGLETONS) if (feature[hook]) claim(hook, feature)\n const blocks = feature.blocks\n if (!blocks) continue\n if (blocks.normalize) normalizers.push(blocks.normalize)\n for (const hook of SINGLETON_PIPELINE_HOOKS) {\n const fn = blocks[hook]\n if (!fn) continue\n claim(hook, feature)\n Object.assign(pipeline, { [hook]: fn })\n }\n }\n if (normalizers.length) pipeline.normalize = (editor, blocks) => normalizers.reduce((current, normalize) => normalize(editor, current), blocks)\n\n const conversions: ConversionProvider[] = features.flatMap(feature => [...(feature.conversions ?? [])])\n const contexts = features.flatMap(feature => feature.aiContext ? [{ id: feature.id, read: feature.aiContext }] : [])\n const aiContext = contexts.length\n ? (editor: Editor): AiContext => {\n const merged: { kinds: AiContextKind[], blocks: AiBlock[], structure?: AiContext['structure'], owner?: string } = { kinds: [], blocks: [] }\n const blockIds = new Set<string>()\n for (const { id, read } of contexts) {\n const context = read(editor)\n merged.kinds.push(...(context.kinds ?? []))\n for (const block of context.blocks ?? []) {\n if (blockIds.has(block.id)) fail(`the AI block \"${block.id}\" is described by more than one feature`)\n blockIds.add(block.id)\n merged.blocks.push(block)\n }\n if (context.structure === undefined) continue\n if (merged.owner) fail(`features \"${merged.owner}\" and \"${id}\" both set aiContext.structure`)\n merged.owner = id\n merged.structure = context.structure\n }\n return { kinds: merged.kinds, blocks: merged.blocks, ...(merged.structure && { structure: merged.structure }) }\n }\n : undefined\n const dataProviders = features.flatMap(feature => feature.aiBlockData ? [feature.aiBlockData] : [])\n const aiBlockData: AiBlockDataProvider | undefined = dataProviders.length\n ? async request => (await Promise.all(dataProviders.map(provide => provide(request)))).flat()\n : undefined\n const formatAiResult = features.find(feature => feature.formatAiResult)?.formatAiResult\n return Object.freeze({\n features,\n pipeline: Object.freeze(pipeline),\n conversions: Object.freeze(conversions),\n ...(aiContext && { aiContext }),\n ...(aiBlockData && { aiBlockData }),\n ...(formatAiResult && { formatAiResult }),\n })\n}\n\n/**\n * The settings tabs the features of `preset` contribute for the app context `ctx` (labels in its language), in feature\n * order; none means there is no settings UI. Throws when two features contribute the same tab id.\n */\nexport function settingsTabsOf<C = unknown>(preset: EditorPreset<C>, ctx: EditorContext): readonly SettingsTab<C>[] {\n const owners = new Map<string, string>()\n return preset.features.flatMap((feature) => {\n const tabs = feature.settingsTabs?.(ctx) ?? []\n for (const tab of tabs) {\n const owner = owners.get(tab.id)\n if (owner) fail(`features \"${owner}\" and \"${feature.id}\" both contribute the settings tab \"${tab.id}\"`)\n owners.set(tab.id, feature.id)\n }\n return tabs\n })\n}\n\n/** Features of `preset` that fill the contribution `key`, in order. */\nexport function contributions<C, K extends keyof EditorFeature<C>>(preset: EditorPreset<C>, key: K): NonNullable<EditorFeature<C>[K]>[] {\n return preset.features.flatMap(feature => feature[key] ? [feature[key] as NonNullable<EditorFeature<C>[K]>] : [])\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"define-editor.js","names":["failWith"],"sources":["../../src/core/define-editor.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { BUILT_IN_BLOCK_CAPABILITIES, type BlockCapability, type BlockTypeData, createCapabilityRegistry } from './capabilities'\nimport { createDeriveRegistry, type DeriveMethod } from './derive'\nimport type { EditorContext } from './context'\nimport { type AiBlock, type AiBlockDataProvider, type AiContext, type AiContextBlockType, type BlockPipeline, type ConversionProvider, type EditorFeature, type EditorPreset, type SettingsTab, SINGLETON_PIPELINE_HOOKS } from './feature'\nimport { DEFAULT_BLOCK_PIPELINE } from './pipeline'\nimport { migratePersistedNames } from './schema/persisted-names'\nimport { fail as failWith } from './util'\n\nconst FEATURE_SINGLETONS = ['anchorResolver', 'formatAiResult'] as const satisfies readonly (keyof EditorFeature)[]\n\nconst fail = (message: string): never => failWith(message, 'defineEditor')\n\n/**\n * Validates `features` and resolves their pipeline and conversion providers. Keeps the given order; neither\n * deduplicates nor installs missing dependencies. Throws on duplicate ids, a `requires` entry that is not installed,\n * a toolbar group declared by two features (`toolbarGroups`), a block capability declared twice or with a built-in id (`blockCapabilities`), a derive method declared twice, with neither `run` nor `menu` or requiring an undeclared capability (`deriveMethods`) and a singleton hook (`parseMarkdown`, `segment`, `structure`, `wrapImport`, `migrateContent`, `anchorResolver`,\n * `formatAiResult`) contributed twice. A command naming a toolbar group no feature declares needs the feature context\n * to build the commands: `toolbarOf` throws it. `normalize` hooks chain left to right. `aiContext` contributions merge (`blockTypes` and `blocks`\n * concatenated in feature order, `structure` from one feature only); their conflicts surface when the merged `aiContext` reads the editor.\n * `aiBlockData` contributions are additive too: they run in parallel per block and their data concatenate in feature order.\n */\nexport function defineEditor<C = unknown>(config: { features: readonly EditorFeature<C>[] }): EditorPreset<C> {\n const features = Object.freeze([...config.features])\n const ids = new Set<string>()\n for (const feature of features) {\n if (!feature.dimension) fail(`feature \"${feature.id}\" declares no dimension`)\n }\n for (const feature of features) {\n if (ids.has(feature.id)) fail(`duplicate feature id \"${feature.id}\"`)\n ids.add(feature.id)\n }\n for (const feature of features) {\n for (const required of feature.requires ?? []) {\n if (!ids.has(required)) fail(`feature \"${feature.id}\" requires \"${required}\", which is not installed`)\n }\n }\n const groups = new Map<string, string>()\n for (const feature of features) {\n for (const group of feature.toolbarGroups ?? []) {\n const owner = groups.get(group.id)\n if (owner) fail(`features \"${owner}\" and \"${feature.id}\" both declare toolbar group \"${group.id}\"`)\n groups.set(group.id, feature.id)\n }\n }\n\n const capabilities: BlockCapability[] = [...BUILT_IN_BLOCK_CAPABILITIES]\n const capabilityOwners = new Map<string, string>(capabilities.map(capability => [capability.id, 'the editor core']))\n for (const feature of features) {\n for (const capability of feature.blockCapabilities ?? []) {\n const owner = capabilityOwners.get(capability.id)\n if (owner) fail(`the block capability \"${capability.id}\" is declared by ${owner} and by feature \"${feature.id}\"`)\n capabilityOwners.set(capability.id, `feature \"${feature.id}\"`)\n capabilities.push(capability)\n }\n }\n\n const deriveMethods: DeriveMethod[] = []\n const deriveOwners = new Map<string, string>()\n for (const feature of features) {\n for (const method of feature.deriveMethods ?? []) {\n const owner = deriveOwners.get(method.id)\n if (owner) fail(`the derive method \"${method.id}\" is declared by feature \"${owner}\" and by feature \"${feature.id}\"`)\n deriveOwners.set(method.id, feature.id)\n if (!method.run === !method.menu) fail(`the derive method \"${method.id}\" of feature \"${feature.id}\" needs exactly one of run and menu`)\n for (const required of method.requires) {\n if (!capabilityOwners.has(required)) fail(`the derive method \"${method.id}\" of feature \"${feature.id}\" requires the capability \"${required}\", which no feature declares`)\n }\n deriveMethods.push(method)\n }\n }\n\n const owners = new Map<string, string>()\n const claim = (hook: string, feature: EditorFeature<C>) => {\n const owner = owners.get(hook)\n if (owner) fail(`features \"${owner}\" and \"${feature.id}\" both contribute the singleton hook \"${hook}\"`)\n owners.set(hook, feature.id)\n }\n const pipeline: BlockPipeline = { ...DEFAULT_BLOCK_PIPELINE }\n const normalizers: BlockPipeline['normalize'][] = []\n for (const feature of features) {\n for (const hook of FEATURE_SINGLETONS) if (feature[hook]) claim(hook, feature)\n const blocks = feature.blocks\n if (!blocks) continue\n if (blocks.normalize) normalizers.push(blocks.normalize)\n for (const hook of SINGLETON_PIPELINE_HOOKS) {\n const fn = blocks[hook]\n if (!fn) continue\n claim(hook, feature)\n Object.assign(pipeline, { [hook]: fn })\n }\n }\n if (normalizers.length) pipeline.normalize = (editor, blocks) => normalizers.reduce((current, normalize) => normalize(editor, current), blocks)\n // The rename of the old persisted names always runs first, so a contributed `migrateContent` only ever sees the current names.\n const contributed = pipeline.migrateContent\n if (contributed !== DEFAULT_BLOCK_PIPELINE.migrateContent) pipeline.migrateContent = content => contributed(migratePersistedNames(content))\n\n const conversions: ConversionProvider[] = features.flatMap(feature => [...(feature.conversions ?? [])])\n const contexts = features.flatMap(feature => feature.aiContext ? [{ id: feature.id, read: feature.aiContext }] : [])\n const aiContext = contexts.length\n ? (editor: Editor): AiContext => {\n const merged: { blockTypes: AiContextBlockType[], blocks: AiBlock[], structure?: AiContext['structure'], owner?: string } = { blockTypes: [], blocks: [] }\n const blockIds = new Set<string>()\n for (const { id, read } of contexts) {\n const context = read(editor)\n merged.blockTypes.push(...(context.blockTypes ?? []))\n for (const block of context.blocks ?? []) {\n if (blockIds.has(block.id)) fail(`the AI block \"${block.id}\" is described by more than one feature`)\n blockIds.add(block.id)\n merged.blocks.push(block)\n }\n if (context.structure === undefined) continue\n if (merged.owner) fail(`features \"${merged.owner}\" and \"${id}\" both set aiContext.structure`)\n merged.owner = id\n merged.structure = context.structure\n }\n return { blockTypes: merged.blockTypes, blocks: merged.blocks, ...(merged.structure && { structure: merged.structure }) }\n }\n : undefined\n const dataProviders = features.flatMap(feature => feature.aiBlockData ? [feature.aiBlockData] : [])\n const aiBlockData: AiBlockDataProvider | undefined = dataProviders.length\n ? async request => (await Promise.all(dataProviders.map(provide => provide(request)))).flat()\n : undefined\n const formatAiResult = features.find(feature => feature.formatAiResult)?.formatAiResult\n const blockTypeSources = features.flatMap(feature => feature.blockTypes ? [feature.blockTypes] : [])\n const blockTypes = blockTypeSources.length\n ? (editor: Editor): readonly BlockTypeData[] => blockTypeSources.length === 1 ? blockTypeSources[0]!(editor) : blockTypeSources.flatMap(source => [...source(editor)])\n : undefined\n return Object.freeze({\n features,\n pipeline: Object.freeze(pipeline),\n conversions: Object.freeze(conversions),\n capabilities: createCapabilityRegistry(Object.freeze(capabilities)),\n deriveMethods: createDeriveRegistry(Object.freeze(deriveMethods)),\n ...(blockTypes && { blockTypes }),\n ...(aiContext && { aiContext }),\n ...(aiBlockData && { aiBlockData }),\n ...(formatAiResult && { formatAiResult }),\n })\n}\n\n/**\n * The settings tabs the features of `preset` contribute for the app context `ctx` (labels in its language), in feature\n * order; none means there is no settings UI. Throws when two features contribute the same tab id.\n */\nexport function settingsTabsOf<C = unknown>(preset: EditorPreset<C>, ctx: EditorContext): readonly SettingsTab<C>[] {\n const owners = new Map<string, string>()\n return preset.features.flatMap((feature) => {\n const tabs = feature.settingsTabs?.(ctx) ?? []\n for (const tab of tabs) {\n const owner = owners.get(tab.id)\n if (owner) fail(`features \"${owner}\" and \"${feature.id}\" both contribute the settings tab \"${tab.id}\"`)\n owners.set(tab.id, feature.id)\n }\n return tabs\n })\n}\n\n/** Features of `preset` that fill the contribution `key`, in order. */\nexport function contributions<C, K extends keyof EditorFeature<C>>(preset: EditorPreset<C>, key: K): NonNullable<EditorFeature<C>[K]>[] {\n return preset.features.flatMap(feature => feature[key] ? [feature[key] as NonNullable<EditorFeature<C>[K]>] : [])\n}\n"],"mappings":";;;;;;;AASA,MAAM,qBAAqB,CAAC,kBAAkB,gBAAgB;AAE9D,MAAM,QAAQ,YAA2BA,OAAS,SAAS,cAAc;;;;;;;;;;AAWzE,SAAgB,aAA0B,QAAoE;CAC5G,MAAM,WAAW,OAAO,OAAO,CAAC,GAAG,OAAO,QAAQ,CAAC;CACnD,MAAM,sBAAM,IAAI,IAAY;CAC5B,KAAK,MAAM,WAAW,UACpB,IAAI,CAAC,QAAQ,WAAW,KAAK,YAAY,QAAQ,GAAG,wBAAwB;CAE9E,KAAK,MAAM,WAAW,UAAU;EAC9B,IAAI,IAAI,IAAI,QAAQ,EAAE,GAAG,KAAK,yBAAyB,QAAQ,GAAG,EAAE;EACpE,IAAI,IAAI,QAAQ,EAAE;CACpB;CACA,KAAK,MAAM,WAAW,UACpB,KAAK,MAAM,YAAY,QAAQ,YAAY,CAAC,GAC1C,IAAI,CAAC,IAAI,IAAI,QAAQ,GAAG,KAAK,YAAY,QAAQ,GAAG,cAAc,SAAS,0BAA0B;CAGzG,MAAM,yBAAS,IAAI,IAAoB;CACvC,KAAK,MAAM,WAAW,UACpB,KAAK,MAAM,SAAS,QAAQ,iBAAiB,CAAC,GAAG;EAC/C,MAAM,QAAQ,OAAO,IAAI,MAAM,EAAE;EACjC,IAAI,OAAO,KAAK,aAAa,MAAM,SAAS,QAAQ,GAAG,gCAAgC,MAAM,GAAG,EAAE;EAClG,OAAO,IAAI,MAAM,IAAI,QAAQ,EAAE;CACjC;CAGF,MAAM,eAAkC,CAAC,GAAG,2BAA2B;CACvE,MAAM,mBAAmB,IAAI,IAAoB,aAAa,KAAI,eAAc,CAAC,WAAW,IAAI,iBAAiB,CAAC,CAAC;CACnH,KAAK,MAAM,WAAW,UACpB,KAAK,MAAM,cAAc,QAAQ,qBAAqB,CAAC,GAAG;EACxD,MAAM,QAAQ,iBAAiB,IAAI,WAAW,EAAE;EAChD,IAAI,OAAO,KAAK,yBAAyB,WAAW,GAAG,mBAAmB,MAAM,mBAAmB,QAAQ,GAAG,EAAE;EAChH,iBAAiB,IAAI,WAAW,IAAI,YAAY,QAAQ,GAAG,EAAE;EAC7D,aAAa,KAAK,UAAU;CAC9B;CAGF,MAAM,gBAAgC,CAAC;CACvC,MAAM,+BAAe,IAAI,IAAoB;CAC7C,KAAK,MAAM,WAAW,UACpB,KAAK,MAAM,UAAU,QAAQ,iBAAiB,CAAC,GAAG;EAChD,MAAM,QAAQ,aAAa,IAAI,OAAO,EAAE;EACxC,IAAI,OAAO,KAAK,sBAAsB,OAAO,GAAG,4BAA4B,MAAM,oBAAoB,QAAQ,GAAG,EAAE;EACnH,aAAa,IAAI,OAAO,IAAI,QAAQ,EAAE;EACtC,IAAI,CAAC,OAAO,QAAQ,CAAC,OAAO,MAAM,KAAK,sBAAsB,OAAO,GAAG,gBAAgB,QAAQ,GAAG,oCAAoC;EACtI,KAAK,MAAM,YAAY,OAAO,UAC5B,IAAI,CAAC,iBAAiB,IAAI,QAAQ,GAAG,KAAK,sBAAsB,OAAO,GAAG,gBAAgB,QAAQ,GAAG,6BAA6B,SAAS,6BAA6B;EAE1K,cAAc,KAAK,MAAM;CAC3B;CAGF,MAAM,yBAAS,IAAI,IAAoB;CACvC,MAAM,SAAS,MAAc,YAA8B;EACzD,MAAM,QAAQ,OAAO,IAAI,IAAI;EAC7B,IAAI,OAAO,KAAK,aAAa,MAAM,SAAS,QAAQ,GAAG,wCAAwC,KAAK,EAAE;EACtG,OAAO,IAAI,MAAM,QAAQ,EAAE;CAC7B;CACA,MAAM,WAA0B,EAAE,GAAG,uBAAuB;CAC5D,MAAM,cAA4C,CAAC;CACnD,KAAK,MAAM,WAAW,UAAU;EAC9B,KAAK,MAAM,QAAQ,oBAAoB,IAAI,QAAQ,OAAO,MAAM,MAAM,OAAO;EAC7E,MAAM,SAAS,QAAQ;EACvB,IAAI,CAAC,QAAQ;EACb,IAAI,OAAO,WAAW,YAAY,KAAK,OAAO,SAAS;EACvD,KAAK,MAAM,QAAQ,0BAA0B;GAC3C,MAAM,KAAK,OAAO;GAClB,IAAI,CAAC,IAAI;GACT,MAAM,MAAM,OAAO;GACnB,OAAO,OAAO,UAAU,GAAG,OAAO,GAAG,CAAC;EACxC;CACF;CACA,IAAI,YAAY,QAAQ,SAAS,aAAa,QAAQ,WAAW,YAAY,QAAQ,SAAS,cAAc,UAAU,QAAQ,OAAO,GAAG,MAAM;CAE9I,MAAM,cAAc,SAAS;CAC7B,IAAI,gBAAgB,uBAAuB,gBAAgB,SAAS,kBAAiB,YAAW,YAAY,sBAAsB,OAAO,CAAC;CAE1I,MAAM,cAAoC,SAAS,SAAQ,YAAW,CAAC,GAAI,QAAQ,eAAe,CAAC,CAAE,CAAC;CACtG,MAAM,WAAW,SAAS,SAAQ,YAAW,QAAQ,YAAY,CAAC;EAAE,IAAI,QAAQ;EAAI,MAAM,QAAQ;CAAU,CAAC,IAAI,CAAC,CAAC;CACnH,MAAM,YAAY,SAAS,UACtB,WAA8B;EAC7B,MAAM,SAAsH;GAAE,YAAY,CAAC;GAAG,QAAQ,CAAC;EAAE;EACzJ,MAAM,2BAAW,IAAI,IAAY;EACjC,KAAK,MAAM,EAAE,IAAI,UAAU,UAAU;GACnC,MAAM,UAAU,KAAK,MAAM;GAC3B,OAAO,WAAW,KAAK,GAAI,QAAQ,cAAc,CAAC,CAAE;GACpD,KAAK,MAAM,SAAS,QAAQ,UAAU,CAAC,GAAG;IACxC,IAAI,SAAS,IAAI,MAAM,EAAE,GAAG,KAAK,iBAAiB,MAAM,GAAG,wCAAwC;IACnG,SAAS,IAAI,MAAM,EAAE;IACrB,OAAO,OAAO,KAAK,KAAK;GAC1B;GACA,IAAI,QAAQ,cAAc,KAAA,GAAW;GACrC,IAAI,OAAO,OAAO,KAAK,aAAa,OAAO,MAAM,SAAS,GAAG,+BAA+B;GAC5F,OAAO,QAAQ;GACf,OAAO,YAAY,QAAQ;EAC7B;EACA,OAAO;GAAE,YAAY,OAAO;GAAY,QAAQ,OAAO;GAAQ,GAAI,OAAO,aAAa,EAAE,WAAW,OAAO,UAAU;EAAG;CAC1H,IACA,KAAA;CACJ,MAAM,gBAAgB,SAAS,SAAQ,YAAW,QAAQ,cAAc,CAAC,QAAQ,WAAW,IAAI,CAAC,CAAC;CAClG,MAAM,cAA+C,cAAc,SAC/D,OAAM,aAAY,MAAM,QAAQ,IAAI,cAAc,KAAI,YAAW,QAAQ,OAAO,CAAC,CAAC,EAAA,CAAG,KAAK,IAC1F,KAAA;CACJ,MAAM,iBAAiB,SAAS,MAAK,YAAW,QAAQ,cAAc,CAAC,EAAE;CACzE,MAAM,mBAAmB,SAAS,SAAQ,YAAW,QAAQ,aAAa,CAAC,QAAQ,UAAU,IAAI,CAAC,CAAC;CACnG,MAAM,aAAa,iBAAiB,UAC/B,WAA6C,iBAAiB,WAAW,IAAI,iBAAiB,EAAE,CAAE,MAAM,IAAI,iBAAiB,SAAQ,WAAU,CAAC,GAAG,OAAO,MAAM,CAAC,CAAC,IACnK,KAAA;CACJ,OAAO,OAAO,OAAO;EACnB;EACA,UAAU,OAAO,OAAO,QAAQ;EAChC,aAAa,OAAO,OAAO,WAAW;EACtC,cAAc,yBAAyB,OAAO,OAAO,YAAY,CAAC;EAClE,eAAe,qBAAqB,OAAO,OAAO,aAAa,CAAC;EAChE,GAAI,cAAc,EAAE,WAAW;EAC/B,GAAI,aAAa,EAAE,UAAU;EAC7B,GAAI,eAAe,EAAE,YAAY;EACjC,GAAI,kBAAkB,EAAE,eAAe;CACzC,CAAC;AACH;;;;;AAMA,SAAgB,eAA4B,QAAyB,KAA+C;CAClH,MAAM,yBAAS,IAAI,IAAoB;CACvC,OAAO,OAAO,SAAS,SAAS,YAAY;EAC1C,MAAM,OAAO,QAAQ,eAAe,GAAG,KAAK,CAAC;EAC7C,KAAK,MAAM,OAAO,MAAM;GACtB,MAAM,QAAQ,OAAO,IAAI,IAAI,EAAE;GAC/B,IAAI,OAAO,KAAK,aAAa,MAAM,SAAS,QAAQ,GAAG,sCAAsC,IAAI,GAAG,EAAE;GACtG,OAAO,IAAI,IAAI,IAAI,QAAQ,EAAE;EAC/B;EACA,OAAO;CACT,CAAC;AACH;;AAGA,SAAgB,cAAmD,QAAyB,KAA4C;CACtI,OAAO,OAAO,SAAS,SAAQ,YAAW,QAAQ,OAAO,CAAC,QAAQ,IAAwC,IAAI,CAAC,CAAC;AAClH"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Node } from "@tiptap/pm/model";
|
|
2
|
+
//#region src/core/derivation.d.ts
|
|
3
|
+
/** `meta` key of a Derivation. */
|
|
4
|
+
export declare const DERIVATION_KEY = "derivation";
|
|
5
|
+
/** How a Derived block was made; `ai:<typeId>` for a block derived from another block by the model. */
|
|
6
|
+
export type DerivationMethod = 'transcription' | 'pdf-text' | 'ocr' | 'description' | 'bibliography' | (string & {});
|
|
7
|
+
/** What a Derived block was made from: an uploaded asset (by asset name) or another block (by block id). */
|
|
8
|
+
export type DerivationSource = {
|
|
9
|
+
asset: string;
|
|
10
|
+
} | {
|
|
11
|
+
block: string; /** Document the block lives in; absent = this document. */
|
|
12
|
+
document?: string;
|
|
13
|
+
};
|
|
14
|
+
/** `meta.derivation` of a Derived block. */
|
|
15
|
+
export interface Derivation {
|
|
16
|
+
from: DerivationSource;
|
|
17
|
+
method: DerivationMethod;
|
|
18
|
+
model?: string;
|
|
19
|
+
/** ISO timestamp. */
|
|
20
|
+
createdAt: string;
|
|
21
|
+
/** SHA-256 hex of the asset bytes / of the source block's Markdown; `''` when unknown. */
|
|
22
|
+
inputHash: string;
|
|
23
|
+
/** SHA-256 hex of the produced body's Markdown; `''` when unknown. */
|
|
24
|
+
outputHash: string;
|
|
25
|
+
/** Asset name of the stored raw output (text/markdown). */
|
|
26
|
+
output?: string;
|
|
27
|
+
}
|
|
28
|
+
/** The derivation of a block (`meta.derivation` with a `from` object and a `method`); null when it has none. */
|
|
29
|
+
export declare function derivationOf(node: Node): Derivation | null;
|
|
30
|
+
/** Whether `derivation` points at a block of another document than `documentId` (the open one; null/undefined = unknown, so any named document is another). */
|
|
31
|
+
export declare function isForeignSource(derivation: Derivation, documentId: string | null | undefined): boolean;
|
|
32
|
+
/** The stored asset behind an `/api/editor/assets/<documentId>/<name>` URL; null for any other `src`. */
|
|
33
|
+
export declare function assetRefOf(src: string): {
|
|
34
|
+
documentId: string;
|
|
35
|
+
name: string;
|
|
36
|
+
} | null;
|
|
37
|
+
/** The direct children of `parent` that are Derived blocks, with their child index. */
|
|
38
|
+
export declare function derivedChildrenOf(parent: Node): {
|
|
39
|
+
node: Node;
|
|
40
|
+
index: number;
|
|
41
|
+
derivation: Derivation;
|
|
42
|
+
}[];
|
|
43
|
+
/** A Derived block of the document with its position. */
|
|
44
|
+
export interface DerivedEntry {
|
|
45
|
+
node: Node;
|
|
46
|
+
pos: number;
|
|
47
|
+
derivation: Derivation;
|
|
48
|
+
}
|
|
49
|
+
/** A block that holds a stored asset (its `src`), with the block around it (the holder) when there is one. */
|
|
50
|
+
export interface AssetBlock {
|
|
51
|
+
node: Node;
|
|
52
|
+
pos: number;
|
|
53
|
+
/** Position and size of the enclosing block of the asset block; the document itself has none. */
|
|
54
|
+
holder: {
|
|
55
|
+
pos: number;
|
|
56
|
+
size: number;
|
|
57
|
+
} | null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The reverse index of one document version: Derived blocks by what they were made from, and the blocks they can have been
|
|
61
|
+
* made from by block ID and by asset name. Computed from the document alone and memoised per `doc` node (`derivationIndexOf`),
|
|
62
|
+
* so it is exactly as current as the document it was read from: a move or delete produces a new `doc` and with it a new index.
|
|
63
|
+
*/
|
|
64
|
+
export interface DerivationIndex {
|
|
65
|
+
/** Every Derived block, in document order. */
|
|
66
|
+
readonly derived: readonly DerivedEntry[];
|
|
67
|
+
/** The block with block ID `id` (any depth) and its position; null when the document has none. */
|
|
68
|
+
blockById: (id: string) => {
|
|
69
|
+
node: Node;
|
|
70
|
+
pos: number;
|
|
71
|
+
} | null;
|
|
72
|
+
/** The blocks that hold the stored asset `name`, in document order. */
|
|
73
|
+
assetBlocks: (name: string) => readonly AssetBlock[];
|
|
74
|
+
/** The Derived blocks whose Derivation points at block `id`, in this or any document (`isForeignSource` tells them apart). */
|
|
75
|
+
derivedFromBlock: (id: string) => readonly DerivedEntry[];
|
|
76
|
+
/** The Derived blocks whose Derivation points at the stored asset `name`. */
|
|
77
|
+
derivedFromAsset: (name: string) => readonly DerivedEntry[];
|
|
78
|
+
}
|
|
79
|
+
/** The derivation index of `doc`, built once per document version (the `doc` node is immutable, so an edit yields a new index). */
|
|
80
|
+
export declare function derivationIndexOf(doc: Node): DerivationIndex;
|
|
81
|
+
/**
|
|
82
|
+
* The Derived blocks made from the original at `originalPos` (a Block in `doc`), in document order. They point at its block ID, or
|
|
83
|
+
* at an asset the original holds as a direct child (its source media); a Derived block moved out of the original still counts. When
|
|
84
|
+
* several blocks hold the same asset (a duplicated Typed block), a Derived block belongs to the holder that contains it, else to the first
|
|
85
|
+
* holder. Derivations from another document (`isForeignSource` against `documentId`) are not listed.
|
|
86
|
+
*/
|
|
87
|
+
export declare function derivedOf(doc: Node, originalPos: number, documentId?: string | null): DerivedEntry[];
|
|
88
|
+
/** Where a Derived block's original is: in this document, in another document (not looked up here) or gone. */
|
|
89
|
+
export type DerivationOrigin = {
|
|
90
|
+
status: 'found';
|
|
91
|
+
node: Node;
|
|
92
|
+
pos: number;
|
|
93
|
+
} | {
|
|
94
|
+
status: 'foreign';
|
|
95
|
+
} | {
|
|
96
|
+
status: 'missing';
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* The original of the Derived block at `derivedPos`: for a block source the block with that ID, for an asset source the block that
|
|
100
|
+
* holds the asset (the one next to the Derived block when several do). `missing` is the source-missing state: the original was
|
|
101
|
+
* deleted, so the Derived block stays without it. Null when the node at `derivedPos` is not a Derived block.
|
|
102
|
+
*/
|
|
103
|
+
export declare function derivationOriginOf(doc: Node, derivedPos: number, documentId?: string | null): DerivationOrigin | null;
|
|
104
|
+
/** What is known about a Derived block against its original. */
|
|
105
|
+
export interface DerivationState {
|
|
106
|
+
/** `missing` is the source-missing state; `foreign` means the original lives in another document and is not looked up. */
|
|
107
|
+
source: DerivationOrigin['status'];
|
|
108
|
+
/**
|
|
109
|
+
* The original changed since the Derived block was made. Only an asset source can be told here (its stored `hash` against
|
|
110
|
+
* `inputHash`); null otherwise, also for a block source: callers with the editor compare the hash of the source's Markdown.
|
|
111
|
+
*/
|
|
112
|
+
stale: boolean | null;
|
|
113
|
+
/** The body's hash (computed lazily, it serialises the body) differs from `outputHash`; null when `outputHash` is unknown. */
|
|
114
|
+
edited: boolean | null;
|
|
115
|
+
}
|
|
116
|
+
/** The state of the Derived block at `derivedPos` of `doc`; null when the node there is not a Derived block. */
|
|
117
|
+
export declare function derivationState(doc: Node, derivedPos: number, bodyHash: () => string, documentId?: string | null): DerivationState | null;
|
|
118
|
+
//#endregion
|
|
119
|
+
//# sourceMappingURL=derivation.d.ts.map
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { blockIdOf } from "./schema/block-ids.js";
|
|
2
|
+
import { EDITOR_API } from "./api-routes.js";
|
|
3
|
+
//#region src/core/derivation.ts
|
|
4
|
+
/** `meta` key of a Derivation. */
|
|
5
|
+
const DERIVATION_KEY = "derivation";
|
|
6
|
+
/** The derivation of a block (`meta.derivation` with a `from` object and a `method`); null when it has none. */
|
|
7
|
+
function derivationOf(node) {
|
|
8
|
+
const meta = node.attrs.meta;
|
|
9
|
+
const value = meta && typeof meta === "object" ? meta[DERIVATION_KEY] : void 0;
|
|
10
|
+
if (!value || typeof value !== "object") return null;
|
|
11
|
+
const { from, method } = value;
|
|
12
|
+
if (!from || typeof from !== "object" || typeof method !== "string") return null;
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
/** Whether `derivation` points at a block of another document than `documentId` (the open one; null/undefined = unknown, so any named document is another). */
|
|
16
|
+
function isForeignSource(derivation, documentId) {
|
|
17
|
+
return "block" in derivation.from && !!derivation.from.document && derivation.from.document !== documentId;
|
|
18
|
+
}
|
|
19
|
+
const ASSET_URL_PREFIX = `${EDITOR_API}/assets/`;
|
|
20
|
+
const ASSET_NAME = /^[0-9a-f-]{36}\.[a-z0-9]{1,8}$/;
|
|
21
|
+
const ASSET_DOCUMENT_ID = /^[A-Za-z0-9_-]{1,64}$/;
|
|
22
|
+
/** The stored asset behind an `/api/editor/assets/<documentId>/<name>` URL; null for any other `src`. */
|
|
23
|
+
function assetRefOf(src) {
|
|
24
|
+
if (!src.startsWith(ASSET_URL_PREFIX)) return null;
|
|
25
|
+
const [documentId, name, ...rest] = src.slice(ASSET_URL_PREFIX.length).split("/");
|
|
26
|
+
if (rest.length || !documentId || !name || !ASSET_DOCUMENT_ID.test(documentId) || !ASSET_NAME.test(name)) return null;
|
|
27
|
+
return {
|
|
28
|
+
documentId,
|
|
29
|
+
name
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** The direct children of `parent` that are Derived blocks, with their child index. */
|
|
33
|
+
function derivedChildrenOf(parent) {
|
|
34
|
+
const found = [];
|
|
35
|
+
parent.forEach((node, _offset, index) => {
|
|
36
|
+
const derivation = derivationOf(node);
|
|
37
|
+
if (derivation) found.push({
|
|
38
|
+
node,
|
|
39
|
+
index,
|
|
40
|
+
derivation
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
return found;
|
|
44
|
+
}
|
|
45
|
+
const NONE = [];
|
|
46
|
+
function buildIndex(doc) {
|
|
47
|
+
const derived = [];
|
|
48
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
49
|
+
const assets = /* @__PURE__ */ new Map();
|
|
50
|
+
const byBlock = /* @__PURE__ */ new Map();
|
|
51
|
+
const byAsset = /* @__PURE__ */ new Map();
|
|
52
|
+
const push = (map, key, value) => {
|
|
53
|
+
const list = map.get(key);
|
|
54
|
+
if (list) list.push(value);
|
|
55
|
+
else map.set(key, [value]);
|
|
56
|
+
};
|
|
57
|
+
doc.descendants((node, pos) => {
|
|
58
|
+
if (node.isText) return false;
|
|
59
|
+
const id = blockIdOf(node);
|
|
60
|
+
if (id && !blocks.has(id)) blocks.set(id, {
|
|
61
|
+
node,
|
|
62
|
+
pos
|
|
63
|
+
});
|
|
64
|
+
const derivation = derivationOf(node);
|
|
65
|
+
if (derivation) {
|
|
66
|
+
const entry = {
|
|
67
|
+
node,
|
|
68
|
+
pos,
|
|
69
|
+
derivation
|
|
70
|
+
};
|
|
71
|
+
derived.push(entry);
|
|
72
|
+
if ("block" in derivation.from) push(byBlock, derivation.from.block, entry);
|
|
73
|
+
else push(byAsset, derivation.from.asset, entry);
|
|
74
|
+
}
|
|
75
|
+
const src = node.attrs.src;
|
|
76
|
+
const asset = typeof src === "string" ? assetRefOf(src) : null;
|
|
77
|
+
if (asset) {
|
|
78
|
+
const $pos = doc.resolve(pos);
|
|
79
|
+
push(assets, asset.name, {
|
|
80
|
+
node,
|
|
81
|
+
pos,
|
|
82
|
+
holder: $pos.depth > 0 ? {
|
|
83
|
+
pos: $pos.before($pos.depth),
|
|
84
|
+
size: $pos.parent.nodeSize
|
|
85
|
+
} : null
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return !node.isTextblock;
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
derived,
|
|
92
|
+
blockById: (id) => blocks.get(id) ?? null,
|
|
93
|
+
assetBlocks: (name) => assets.get(name) ?? NONE,
|
|
94
|
+
derivedFromBlock: (id) => byBlock.get(id) ?? NONE,
|
|
95
|
+
derivedFromAsset: (name) => byAsset.get(name) ?? NONE
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const INDEXES = /* @__PURE__ */ new WeakMap();
|
|
99
|
+
/** The derivation index of `doc`, built once per document version (the `doc` node is immutable, so an edit yields a new index). */
|
|
100
|
+
function derivationIndexOf(doc) {
|
|
101
|
+
let index = INDEXES.get(doc);
|
|
102
|
+
if (!index) INDEXES.set(doc, index = buildIndex(doc));
|
|
103
|
+
return index;
|
|
104
|
+
}
|
|
105
|
+
const within = (pos, range) => range.pos < pos && pos < range.pos + range.size;
|
|
106
|
+
/**
|
|
107
|
+
* The Derived blocks made from the original at `originalPos` (a Block in `doc`), in document order. They point at its block ID, or
|
|
108
|
+
* at an asset the original holds as a direct child (its source media); a Derived block moved out of the original still counts. When
|
|
109
|
+
* several blocks hold the same asset (a duplicated Typed block), a Derived block belongs to the holder that contains it, else to the first
|
|
110
|
+
* holder. Derivations from another document (`isForeignSource` against `documentId`) are not listed.
|
|
111
|
+
*/
|
|
112
|
+
function derivedOf(doc, originalPos, documentId) {
|
|
113
|
+
const original = doc.nodeAt(originalPos);
|
|
114
|
+
if (!original) return [];
|
|
115
|
+
const index = derivationIndexOf(doc);
|
|
116
|
+
const found = /* @__PURE__ */ new Map();
|
|
117
|
+
const id = blockIdOf(original);
|
|
118
|
+
if (id) {
|
|
119
|
+
for (const entry of index.derivedFromBlock(id)) if (!isForeignSource(entry.derivation, documentId)) found.set(entry.pos, entry);
|
|
120
|
+
}
|
|
121
|
+
const range = {
|
|
122
|
+
pos: originalPos,
|
|
123
|
+
size: original.nodeSize
|
|
124
|
+
};
|
|
125
|
+
const names = /* @__PURE__ */ new Set();
|
|
126
|
+
original.forEach((child) => {
|
|
127
|
+
const src = child.attrs.src;
|
|
128
|
+
const asset = typeof src === "string" ? assetRefOf(src) : null;
|
|
129
|
+
if (asset) names.add(asset.name);
|
|
130
|
+
});
|
|
131
|
+
for (const name of names) {
|
|
132
|
+
const holders = index.assetBlocks(name).flatMap((block) => block.holder ? [block.holder] : []);
|
|
133
|
+
for (const entry of index.derivedFromAsset(name)) {
|
|
134
|
+
const owner = holders.find((holder) => within(entry.pos, holder)) ?? holders[0];
|
|
135
|
+
if (owner && owner.pos === range.pos) found.set(entry.pos, entry);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return [...found.values()].sort((a, b) => a.pos - b.pos);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The original of the Derived block at `derivedPos`: for a block source the block with that ID, for an asset source the block that
|
|
142
|
+
* holds the asset (the one next to the Derived block when several do). `missing` is the source-missing state: the original was
|
|
143
|
+
* deleted, so the Derived block stays without it. Null when the node at `derivedPos` is not a Derived block.
|
|
144
|
+
*/
|
|
145
|
+
function derivationOriginOf(doc, derivedPos, documentId) {
|
|
146
|
+
const derived = doc.nodeAt(derivedPos);
|
|
147
|
+
const derivation = derived && derivationOf(derived);
|
|
148
|
+
if (!derivation) return null;
|
|
149
|
+
if (isForeignSource(derivation, documentId)) return { status: "foreign" };
|
|
150
|
+
const index = derivationIndexOf(doc);
|
|
151
|
+
if ("block" in derivation.from) {
|
|
152
|
+
const block = index.blockById(derivation.from.block);
|
|
153
|
+
return block ? {
|
|
154
|
+
status: "found",
|
|
155
|
+
...block
|
|
156
|
+
} : { status: "missing" };
|
|
157
|
+
}
|
|
158
|
+
const candidates = index.assetBlocks(derivation.from.asset);
|
|
159
|
+
const own = candidates.find((candidate) => candidate.holder && within(derivedPos, candidate.holder)) ?? candidates[0];
|
|
160
|
+
return own ? {
|
|
161
|
+
status: "found",
|
|
162
|
+
node: own.node,
|
|
163
|
+
pos: own.pos
|
|
164
|
+
} : { status: "missing" };
|
|
165
|
+
}
|
|
166
|
+
/** The state of the Derived block at `derivedPos` of `doc`; null when the node there is not a Derived block. */
|
|
167
|
+
function derivationState(doc, derivedPos, bodyHash, documentId) {
|
|
168
|
+
const derived = doc.nodeAt(derivedPos);
|
|
169
|
+
const derivation = derived && derivationOf(derived);
|
|
170
|
+
const origin = derivationOriginOf(doc, derivedPos, documentId);
|
|
171
|
+
if (!derivation || !origin) return null;
|
|
172
|
+
let stale = null;
|
|
173
|
+
if (origin.status === "found" && "asset" in derivation.from) {
|
|
174
|
+
const hash = origin.node.attrs.hash;
|
|
175
|
+
stale = typeof hash === "string" && hash && derivation.inputHash ? hash !== derivation.inputHash : null;
|
|
176
|
+
}
|
|
177
|
+
const edited = derivation.outputHash ? bodyHash() !== derivation.outputHash : null;
|
|
178
|
+
return {
|
|
179
|
+
source: origin.status,
|
|
180
|
+
stale,
|
|
181
|
+
edited
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
//#endregion
|
|
185
|
+
export { DERIVATION_KEY, assetRefOf, derivationIndexOf, derivationOf, derivationOriginOf, derivationState, derivedChildrenOf, derivedOf, isForeignSource };
|
|
186
|
+
|
|
187
|
+
//# sourceMappingURL=derivation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derivation.js","names":[],"sources":["../../src/core/derivation.ts"],"sourcesContent":["// Framework-free and server-importable: where a Block's content comes from. A Derived block (transcript, full text, description,\n// AI result, copy) records in `meta.derivation` what it was made from (its Derivation). The link is stored on the Derived block\n// only; the original finds its Derived blocks through an index computed from block IDs and asset names, never through a stored\n// back-pointer, so concurrent edits (Yjs merges, moves, deletes) cannot leave two blocks disagreeing. The `derived` capability\n// (declared by the composites feature, which owns `meta`) reads the record through `derivationOf`.\nimport type { Node as PMNode } from '@tiptap/pm/model'\nimport { EDITOR_API } from './api-routes'\nimport { blockIdOf } from './schema/block-ids'\n\n/** `meta` key of a Derivation. */\nexport const DERIVATION_KEY = 'derivation'\n\n/** How a Derived block was made; `ai:<typeId>` for a block derived from another block by the model. */\nexport type DerivationMethod = 'transcription' | 'pdf-text' | 'ocr' | 'description' | 'bibliography' | (string & {})\n\n/** What a Derived block was made from: an uploaded asset (by asset name) or another block (by block id). */\nexport type DerivationSource = { asset: string } | { block: string, /** Document the block lives in; absent = this document. */ document?: string }\n\n/** `meta.derivation` of a Derived block. */\nexport interface Derivation {\n from: DerivationSource\n method: DerivationMethod\n model?: string\n /** ISO timestamp. */\n createdAt: string\n /** SHA-256 hex of the asset bytes / of the source block's Markdown; `''` when unknown. */\n inputHash: string\n /** SHA-256 hex of the produced body's Markdown; `''` when unknown. */\n outputHash: string\n /** Asset name of the stored raw output (text/markdown). */\n output?: string\n}\n\n/** The derivation of a block (`meta.derivation` with a `from` object and a `method`); null when it has none. */\nexport function derivationOf(node: PMNode): Derivation | null {\n const meta: unknown = node.attrs.meta\n const value = meta && typeof meta === 'object' ? (meta as Record<string, unknown>)[DERIVATION_KEY] : undefined\n if (!value || typeof value !== 'object') return null\n const { from, method } = value as Record<string, unknown>\n if (!from || typeof from !== 'object' || typeof method !== 'string') return null\n return value as Derivation\n}\n\n/** Whether `derivation` points at a block of another document than `documentId` (the open one; null/undefined = unknown, so any named document is another). */\nexport function isForeignSource(derivation: Derivation, documentId: string | null | undefined): boolean {\n return 'block' in derivation.from && !!derivation.from.document && derivation.from.document !== documentId\n}\n\nconst ASSET_URL_PREFIX = `${EDITOR_API}/assets/`\n// Same patterns as `features/media/assets.ts`; copied because core must not import features.\nconst ASSET_NAME = /^[0-9a-f-]{36}\\.[a-z0-9]{1,8}$/\nconst ASSET_DOCUMENT_ID = /^[A-Za-z0-9_-]{1,64}$/\n\n/** The stored asset behind an `/api/editor/assets/<documentId>/<name>` URL; null for any other `src`. */\nexport function assetRefOf(src: string): { documentId: string, name: string } | null {\n if (!src.startsWith(ASSET_URL_PREFIX)) return null\n const [documentId, name, ...rest] = src.slice(ASSET_URL_PREFIX.length).split('/')\n if (rest.length || !documentId || !name || !ASSET_DOCUMENT_ID.test(documentId) || !ASSET_NAME.test(name)) return null\n return { documentId, name }\n}\n\n/** The direct children of `parent` that are Derived blocks, with their child index. */\nexport function derivedChildrenOf(parent: PMNode): { node: PMNode, index: number, derivation: Derivation }[] {\n const found: { node: PMNode, index: number, derivation: Derivation }[] = []\n parent.forEach((node, _offset, index) => {\n const derivation = derivationOf(node)\n if (derivation) found.push({ node, index, derivation })\n })\n return found\n}\n\n/** A Derived block of the document with its position. */\nexport interface DerivedEntry {\n node: PMNode\n pos: number\n derivation: Derivation\n}\n\n/** A block that holds a stored asset (its `src`), with the block around it (the holder) when there is one. */\nexport interface AssetBlock {\n node: PMNode\n pos: number\n /** Position and size of the enclosing block of the asset block; the document itself has none. */\n holder: { pos: number, size: number } | null\n}\n\n/**\n * The reverse index of one document version: Derived blocks by what they were made from, and the blocks they can have been\n * made from by block ID and by asset name. Computed from the document alone and memoised per `doc` node (`derivationIndexOf`),\n * so it is exactly as current as the document it was read from: a move or delete produces a new `doc` and with it a new index.\n */\nexport interface DerivationIndex {\n /** Every Derived block, in document order. */\n readonly derived: readonly DerivedEntry[]\n /** The block with block ID `id` (any depth) and its position; null when the document has none. */\n blockById: (id: string) => { node: PMNode, pos: number } | null\n /** The blocks that hold the stored asset `name`, in document order. */\n assetBlocks: (name: string) => readonly AssetBlock[]\n /** The Derived blocks whose Derivation points at block `id`, in this or any document (`isForeignSource` tells them apart). */\n derivedFromBlock: (id: string) => readonly DerivedEntry[]\n /** The Derived blocks whose Derivation points at the stored asset `name`. */\n derivedFromAsset: (name: string) => readonly DerivedEntry[]\n}\n\nconst NONE: readonly never[] = []\n\nfunction buildIndex(doc: PMNode): DerivationIndex {\n const derived: DerivedEntry[] = []\n const blocks = new Map<string, { node: PMNode, pos: number }>()\n const assets = new Map<string, AssetBlock[]>()\n const byBlock = new Map<string, DerivedEntry[]>()\n const byAsset = new Map<string, DerivedEntry[]>()\n const push = <K, V>(map: Map<K, V[]>, key: K, value: V) => {\n const list = map.get(key)\n if (list) list.push(value)\n else map.set(key, [value])\n }\n doc.descendants((node, pos) => {\n if (node.isText) return false\n const id = blockIdOf(node)\n if (id && !blocks.has(id)) blocks.set(id, { node, pos })\n const derivation = derivationOf(node)\n if (derivation) {\n const entry: DerivedEntry = { node, pos, derivation }\n derived.push(entry)\n if ('block' in derivation.from) push(byBlock, derivation.from.block, entry)\n else push(byAsset, derivation.from.asset, entry)\n }\n const src: unknown = node.attrs.src\n const asset = typeof src === 'string' ? assetRefOf(src) : null\n if (asset) {\n const $pos = doc.resolve(pos)\n push(assets, asset.name, { node, pos, holder: $pos.depth > 0 ? { pos: $pos.before($pos.depth), size: $pos.parent.nodeSize } : null })\n }\n // Inline content holds neither blocks nor assets.\n return !node.isTextblock\n })\n return {\n derived,\n blockById: id => blocks.get(id) ?? null,\n assetBlocks: name => assets.get(name) ?? NONE,\n derivedFromBlock: id => byBlock.get(id) ?? NONE,\n derivedFromAsset: name => byAsset.get(name) ?? NONE,\n }\n}\n\nconst INDEXES = new WeakMap<PMNode, DerivationIndex>()\n\n/** The derivation index of `doc`, built once per document version (the `doc` node is immutable, so an edit yields a new index). */\nexport function derivationIndexOf(doc: PMNode): DerivationIndex {\n let index = INDEXES.get(doc)\n if (!index) INDEXES.set(doc, index = buildIndex(doc))\n return index\n}\n\nconst within = (pos: number, range: { pos: number, size: number }) => range.pos < pos && pos < range.pos + range.size\n\n/**\n * The Derived blocks made from the original at `originalPos` (a Block in `doc`), in document order. They point at its block ID, or\n * at an asset the original holds as a direct child (its source media); a Derived block moved out of the original still counts. When\n * several blocks hold the same asset (a duplicated Typed block), a Derived block belongs to the holder that contains it, else to the first\n * holder. Derivations from another document (`isForeignSource` against `documentId`) are not listed.\n */\nexport function derivedOf(doc: PMNode, originalPos: number, documentId?: string | null): DerivedEntry[] {\n const original = doc.nodeAt(originalPos)\n if (!original) return []\n const index = derivationIndexOf(doc)\n const found = new Map<number, DerivedEntry>()\n const id = blockIdOf(original)\n if (id) for (const entry of index.derivedFromBlock(id)) if (!isForeignSource(entry.derivation, documentId)) found.set(entry.pos, entry)\n const range = { pos: originalPos, size: original.nodeSize }\n const names = new Set<string>()\n original.forEach((child) => {\n const src: unknown = child.attrs.src\n const asset = typeof src === 'string' ? assetRefOf(src) : null\n if (asset) names.add(asset.name)\n })\n for (const name of names) {\n const holders = index.assetBlocks(name).flatMap(block => block.holder ? [block.holder] : [])\n for (const entry of index.derivedFromAsset(name)) {\n const owner = holders.find(holder => within(entry.pos, holder)) ?? holders[0]\n if (owner && owner.pos === range.pos) found.set(entry.pos, entry)\n }\n }\n return [...found.values()].sort((a, b) => a.pos - b.pos)\n}\n\n/** Where a Derived block's original is: in this document, in another document (not looked up here) or gone. */\nexport type DerivationOrigin\n = | { status: 'found', node: PMNode, pos: number }\n | { status: 'foreign' }\n | { status: 'missing' }\n\n/**\n * The original of the Derived block at `derivedPos`: for a block source the block with that ID, for an asset source the block that\n * holds the asset (the one next to the Derived block when several do). `missing` is the source-missing state: the original was\n * deleted, so the Derived block stays without it. Null when the node at `derivedPos` is not a Derived block.\n */\nexport function derivationOriginOf(doc: PMNode, derivedPos: number, documentId?: string | null): DerivationOrigin | null {\n const derived = doc.nodeAt(derivedPos)\n const derivation = derived && derivationOf(derived)\n if (!derivation) return null\n if (isForeignSource(derivation, documentId)) return { status: 'foreign' }\n const index = derivationIndexOf(doc)\n if ('block' in derivation.from) {\n const block = index.blockById(derivation.from.block)\n return block ? { status: 'found', ...block } : { status: 'missing' }\n }\n const candidates = index.assetBlocks(derivation.from.asset)\n const own = candidates.find(candidate => candidate.holder && within(derivedPos, candidate.holder)) ?? candidates[0]\n return own ? { status: 'found', node: own.node, pos: own.pos } : { status: 'missing' }\n}\n\n/** What is known about a Derived block against its original. */\nexport interface DerivationState {\n /** `missing` is the source-missing state; `foreign` means the original lives in another document and is not looked up. */\n source: DerivationOrigin['status']\n /**\n * The original changed since the Derived block was made. Only an asset source can be told here (its stored `hash` against\n * `inputHash`); null otherwise, also for a block source: callers with the editor compare the hash of the source's Markdown.\n */\n stale: boolean | null\n /** The body's hash (computed lazily, it serialises the body) differs from `outputHash`; null when `outputHash` is unknown. */\n edited: boolean | null\n}\n\n/** The state of the Derived block at `derivedPos` of `doc`; null when the node there is not a Derived block. */\nexport function derivationState(doc: PMNode, derivedPos: number, bodyHash: () => string, documentId?: string | null): DerivationState | null {\n const derived = doc.nodeAt(derivedPos)\n const derivation = derived && derivationOf(derived)\n const origin = derivationOriginOf(doc, derivedPos, documentId)\n if (!derivation || !origin) return null\n let stale: boolean | null = null\n if (origin.status === 'found' && 'asset' in derivation.from) {\n const hash: unknown = origin.node.attrs.hash\n stale = typeof hash === 'string' && hash && derivation.inputHash ? hash !== derivation.inputHash : null\n }\n const edited = derivation.outputHash ? bodyHash() !== derivation.outputHash : null\n return { source: origin.status, stale, edited }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Ability } from "./schema/abilities.js";
|
|
2
|
+
import { MenuItem } from "./command-types.js";
|
|
3
|
+
import { BlockAction } from "./extension-points.js";
|
|
4
|
+
import { EditorPreset, FeatureContext } from "./feature.js";
|
|
5
|
+
import { Editor } from "@tiptap/core";
|
|
6
|
+
import { Node as Node$1 } from "@tiptap/pm/model";
|
|
7
|
+
//#region src/core/derive.d.ts
|
|
8
|
+
/** What a method reads: the original block (`node` at `pos`), its editor and the surface's context (backend, public AI flags, settings, notices, translations). */
|
|
9
|
+
export interface DeriveContext {
|
|
10
|
+
editor: Editor;
|
|
11
|
+
node: Node$1;
|
|
12
|
+
/** Position right before `node`. */
|
|
13
|
+
pos: number;
|
|
14
|
+
ctx: FeatureContext;
|
|
15
|
+
}
|
|
16
|
+
interface DeriveMethodBase {
|
|
17
|
+
/** Unique across the preset; also the id of the block action generated from the method. */
|
|
18
|
+
id: string;
|
|
19
|
+
/** Menu label, in the language of the surface (`ctx.t`). */
|
|
20
|
+
label: (ctx: FeatureContext) => string;
|
|
21
|
+
/** Iconify name, e.g. `i-lucide-captions`. */
|
|
22
|
+
icon: string;
|
|
23
|
+
/** Shown only on blocks that have this ability (`BlockAction.ability`). */
|
|
24
|
+
ability?: Ability;
|
|
25
|
+
/** Position among the block actions (`BlockAction.order`). */
|
|
26
|
+
order?: number;
|
|
27
|
+
placement?: BlockAction['placement'];
|
|
28
|
+
/** Capability ids the original must all have (built-in or declared by a Feature); every id must be declared when the preset is defined. */
|
|
29
|
+
requires: readonly string[];
|
|
30
|
+
/** Backend flags and per-block conditions (`backend.ai` or `ai?.transcription` of the feature context `ctx.ctx`, a source that can be read); absent: always available where `requires` holds. */
|
|
31
|
+
available?: (ctx: DeriveContext) => boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* One way to make a new block or text from a block. Either `run`, or `menu` for a method with sub-choices (derive into one of several
|
|
35
|
+
* Block types). The method itself writes the result and, where it creates a Derived block, its Derivation (`Derivation.method`).
|
|
36
|
+
*/
|
|
37
|
+
export type DeriveMethod = DeriveMethodBase & ({
|
|
38
|
+
run: (ctx: DeriveContext) => void;
|
|
39
|
+
menu?: never;
|
|
40
|
+
} | {
|
|
41
|
+
menu: (ctx: DeriveContext) => MenuItem[];
|
|
42
|
+
run?: never;
|
|
43
|
+
});
|
|
44
|
+
/** The merged derive methods of a preset: the declarations, shared by every editor created from it. */
|
|
45
|
+
export interface DeriveRegistry {
|
|
46
|
+
/** In feature order. */
|
|
47
|
+
readonly methods: readonly DeriveMethod[];
|
|
48
|
+
get: (id: string) => DeriveMethod | undefined;
|
|
49
|
+
}
|
|
50
|
+
export declare function createDeriveRegistry(methods: readonly DeriveMethod[]): DeriveRegistry;
|
|
51
|
+
/** The methods that can run on the block at `pos` of `editor`: the block has every capability the method `requires` and its `available` holds. Empty without a block there or without a preset. */
|
|
52
|
+
export declare function deriveMethodsAt(editor: Editor, ctx: FeatureContext, pos: number): readonly DeriveMethod[];
|
|
53
|
+
/**
|
|
54
|
+
* The block actions of the preset's derive methods, one per method, in the shape the block UI renders: `requires` and the
|
|
55
|
+
* ability gate them as they gate every action, `available` is the visibility check. The menu a user sees is unchanged by
|
|
56
|
+
* the consolidation.
|
|
57
|
+
*/
|
|
58
|
+
export declare function deriveActionsOf(preset: EditorPreset, ctx: FeatureContext): BlockAction[];
|
|
59
|
+
//#endregion
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=derive.d.ts.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { nodeAtPos } from "./util.js";
|
|
2
|
+
import { capabilitiesOf } from "./capabilities.js";
|
|
3
|
+
//#region src/core/derive.ts
|
|
4
|
+
function createDeriveRegistry(methods) {
|
|
5
|
+
const byId = new Map(methods.map((method) => [method.id, method]));
|
|
6
|
+
return {
|
|
7
|
+
methods,
|
|
8
|
+
get: (id) => byId.get(id)
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/** The methods that can run on the block at `pos` of `editor`: the block has every capability the method `requires` and its `available` holds. Empty without a block there or without a preset. */
|
|
12
|
+
function deriveMethodsAt(editor, ctx, pos) {
|
|
13
|
+
const methods = editor.storage.editorPreset?.deriveMethods.methods;
|
|
14
|
+
const node = methods?.length ? nodeAtPos(editor.state.doc, pos) : null;
|
|
15
|
+
if (!methods || !node) return [];
|
|
16
|
+
const capabilities = capabilitiesOf(editor, node);
|
|
17
|
+
const at = {
|
|
18
|
+
editor,
|
|
19
|
+
node,
|
|
20
|
+
pos,
|
|
21
|
+
ctx
|
|
22
|
+
};
|
|
23
|
+
return methods.filter((method) => method.requires.every((id) => capabilities.has(id)) && (method.available?.(at) ?? true));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The block actions of the preset's derive methods, one per method, in the shape the block UI renders: `requires` and the
|
|
27
|
+
* ability gate them as they gate every action, `available` is the visibility check. The menu a user sees is unchanged by
|
|
28
|
+
* the consolidation.
|
|
29
|
+
*/
|
|
30
|
+
function deriveActionsOf(preset, ctx) {
|
|
31
|
+
return preset.deriveMethods.methods.map((method) => {
|
|
32
|
+
const base = {
|
|
33
|
+
id: method.id,
|
|
34
|
+
label: method.label(ctx),
|
|
35
|
+
icon: method.icon,
|
|
36
|
+
requires: method.requires,
|
|
37
|
+
...method.ability !== void 0 && { ability: method.ability },
|
|
38
|
+
...method.order !== void 0 && { order: method.order },
|
|
39
|
+
...method.placement && { placement: method.placement },
|
|
40
|
+
...method.available && { isVisible: ({ editor, node, pos }) => method.available({
|
|
41
|
+
editor,
|
|
42
|
+
node,
|
|
43
|
+
pos,
|
|
44
|
+
ctx
|
|
45
|
+
}) }
|
|
46
|
+
};
|
|
47
|
+
return method.menu ? {
|
|
48
|
+
...base,
|
|
49
|
+
menu: ({ editor, node, pos }) => method.menu({
|
|
50
|
+
editor,
|
|
51
|
+
node,
|
|
52
|
+
pos,
|
|
53
|
+
ctx
|
|
54
|
+
})
|
|
55
|
+
} : {
|
|
56
|
+
...base,
|
|
57
|
+
run: ({ editor, node, pos }) => method.run({
|
|
58
|
+
editor,
|
|
59
|
+
node,
|
|
60
|
+
pos,
|
|
61
|
+
ctx
|
|
62
|
+
})
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { createDeriveRegistry, deriveActionsOf, deriveMethodsAt };
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=derive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.js","names":[],"sources":["../../src/core/derive.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { Node as PMNode } from '@tiptap/pm/model'\nimport { capabilitiesOf } from './capabilities'\nimport type { MenuItem } from './command-types'\nimport type { BlockAction } from './extension-points'\nimport type { EditorPreset, FeatureContext } from './feature'\nimport type { Ability } from './schema/abilities'\nimport { nodeAtPos } from './util'\n\n// Framework-free and server-importable. Transcription, text extraction (PDF text, OCR, image description), summary, AI fill, AI\n// derivation into another Block type and bibliography fetch all \"produce something from this block\". Each is one `DeriveMethod`\n// that a Feature contributes through `EditorFeature.deriveMethods`; the preset merges them into one registry, and the block\n// actions the user sees are generated from it (`deriveActionsOf`), so the menu keeps its entries while one registration replaces\n// the separate action, predicate and backend check each used to have.\n\n/** What a method reads: the original block (`node` at `pos`), its editor and the surface's context (backend, public AI flags, settings, notices, translations). */\nexport interface DeriveContext {\n editor: Editor\n node: PMNode\n /** Position right before `node`. */\n pos: number\n ctx: FeatureContext\n}\n\ninterface DeriveMethodBase {\n /** Unique across the preset; also the id of the block action generated from the method. */\n id: string\n /** Menu label, in the language of the surface (`ctx.t`). */\n label: (ctx: FeatureContext) => string\n /** Iconify name, e.g. `i-lucide-captions`. */\n icon: string\n /** Shown only on blocks that have this ability (`BlockAction.ability`). */\n ability?: Ability\n /** Position among the block actions (`BlockAction.order`). */\n order?: number\n placement?: BlockAction['placement']\n /** Capability ids the original must all have (built-in or declared by a Feature); every id must be declared when the preset is defined. */\n requires: readonly string[]\n /** Backend flags and per-block conditions (`backend.ai` or `ai?.transcription` of the feature context `ctx.ctx`, a source that can be read); absent: always available where `requires` holds. */\n available?: (ctx: DeriveContext) => boolean\n}\n\n/**\n * One way to make a new block or text from a block. Either `run`, or `menu` for a method with sub-choices (derive into one of several\n * Block types). The method itself writes the result and, where it creates a Derived block, its Derivation (`Derivation.method`).\n */\nexport type DeriveMethod = DeriveMethodBase & (\n | { run: (ctx: DeriveContext) => void, menu?: never }\n | { menu: (ctx: DeriveContext) => MenuItem[], run?: never }\n)\n\n/** The merged derive methods of a preset: the declarations, shared by every editor created from it. */\nexport interface DeriveRegistry {\n /** In feature order. */\n readonly methods: readonly DeriveMethod[]\n get: (id: string) => DeriveMethod | undefined\n}\n\nexport function createDeriveRegistry(methods: readonly DeriveMethod[]): DeriveRegistry {\n const byId = new Map(methods.map(method => [method.id, method]))\n return { methods, get: id => byId.get(id) }\n}\n\n/** The methods that can run on the block at `pos` of `editor`: the block has every capability the method `requires` and its `available` holds. Empty without a block there or without a preset. */\nexport function deriveMethodsAt(editor: Editor, ctx: FeatureContext, pos: number): readonly DeriveMethod[] {\n const methods = editor.storage.editorPreset?.deriveMethods.methods\n const node = methods?.length ? nodeAtPos(editor.state.doc, pos) : null\n if (!methods || !node) return []\n const capabilities = capabilitiesOf(editor, node)\n const at: DeriveContext = { editor, node, pos, ctx }\n return methods.filter(method => method.requires.every(id => capabilities.has(id)) && (method.available?.(at) ?? true))\n}\n\n/**\n * The block actions of the preset's derive methods, one per method, in the shape the block UI renders: `requires` and the\n * ability gate them as they gate every action, `available` is the visibility check. The menu a user sees is unchanged by\n * the consolidation.\n */\nexport function deriveActionsOf(preset: EditorPreset, ctx: FeatureContext): BlockAction[] {\n return preset.deriveMethods.methods.map((method): BlockAction => {\n const base = {\n id: method.id,\n label: method.label(ctx),\n icon: method.icon,\n requires: method.requires,\n ...(method.ability !== undefined && { ability: method.ability }),\n ...(method.order !== undefined && { order: method.order }),\n ...(method.placement && { placement: method.placement }),\n ...(method.available && { isVisible: ({ editor, node, pos }: { editor: Editor, node: PMNode, pos: number }) => method.available!({ editor, node, pos, ctx }) }),\n }\n return method.menu\n ? { ...base, menu: ({ editor, node, pos }) => method.menu!({ editor, node, pos, ctx }) }\n : { ...base, run: ({ editor, node, pos }) => method.run!({ editor, node, pos, ctx }) }\n })\n}\n"],"mappings":";;;AA0DA,SAAgB,qBAAqB,SAAkD;CACrF,MAAM,OAAO,IAAI,IAAI,QAAQ,KAAI,WAAU,CAAC,OAAO,IAAI,MAAM,CAAC,CAAC;CAC/D,OAAO;EAAE;EAAS,MAAK,OAAM,KAAK,IAAI,EAAE;CAAE;AAC5C;;AAGA,SAAgB,gBAAgB,QAAgB,KAAqB,KAAsC;CACzG,MAAM,UAAU,OAAO,QAAQ,cAAc,cAAc;CAC3D,MAAM,OAAO,SAAS,SAAS,UAAU,OAAO,MAAM,KAAK,GAAG,IAAI;CAClE,IAAI,CAAC,WAAW,CAAC,MAAM,OAAO,CAAC;CAC/B,MAAM,eAAe,eAAe,QAAQ,IAAI;CAChD,MAAM,KAAoB;EAAE;EAAQ;EAAM;EAAK;CAAI;CACnD,OAAO,QAAQ,QAAO,WAAU,OAAO,SAAS,OAAM,OAAM,aAAa,IAAI,EAAE,CAAC,MAAM,OAAO,YAAY,EAAE,KAAK,KAAK;AACvH;;;;;;AAOA,SAAgB,gBAAgB,QAAsB,KAAoC;CACxF,OAAO,OAAO,cAAc,QAAQ,KAAK,WAAwB;EAC/D,MAAM,OAAO;GACX,IAAI,OAAO;GACX,OAAO,OAAO,MAAM,GAAG;GACvB,MAAM,OAAO;GACb,UAAU,OAAO;GACjB,GAAI,OAAO,YAAY,KAAA,KAAa,EAAE,SAAS,OAAO,QAAQ;GAC9D,GAAI,OAAO,UAAU,KAAA,KAAa,EAAE,OAAO,OAAO,MAAM;GACxD,GAAI,OAAO,aAAa,EAAE,WAAW,OAAO,UAAU;GACtD,GAAI,OAAO,aAAa,EAAE,YAAY,EAAE,QAAQ,MAAM,UAAyD,OAAO,UAAW;IAAE;IAAQ;IAAM;IAAK;GAAI,CAAC,EAAE;EAC/J;EACA,OAAO,OAAO,OACV;GAAE,GAAG;GAAM,OAAO,EAAE,QAAQ,MAAM,UAAU,OAAO,KAAM;IAAE;IAAQ;IAAM;IAAK;GAAI,CAAC;EAAE,IACrF;GAAE,GAAG;GAAM,MAAM,EAAE,QAAQ,MAAM,UAAU,OAAO,IAAK;IAAE;IAAQ;IAAM;IAAK;GAAI,CAAC;EAAE;CACzF,CAAC;AACH"}
|