From 3716c62d724b96f9f3b71af3ac2b3764703721fb Mon Sep 17 00:00:00 2001 From: Garrett Jones Date: Fri, 19 Jul 2024 07:39:36 -0500 Subject: [PATCH] Create sofria json render engine --- .../sofria-render-json/RenderContent.svelte | 20 ++++ .../sofria-render-json/RenderParagraph.svelte | 32 ++++++ .../sofria-render-json/RenderSequence.svelte | 18 +++ .../sofria-render-json/RenderWrapper.svelte | 20 ++++ .../sofria-render-json/SofriaRender.svelte | 19 ++++ .../sofria-render-json/schema/paragraphs.ts | 28 +++++ .../schema/sofria-schema.ts | 106 ++++++++++++++++++ .../sofria-render-json/schema/wrappers.ts | 12 ++ 8 files changed, 255 insertions(+) create mode 100644 src/lib/components/sofria-render-json/RenderContent.svelte create mode 100644 src/lib/components/sofria-render-json/RenderParagraph.svelte create mode 100644 src/lib/components/sofria-render-json/RenderSequence.svelte create mode 100644 src/lib/components/sofria-render-json/RenderWrapper.svelte create mode 100644 src/lib/components/sofria-render-json/SofriaRender.svelte create mode 100644 src/lib/components/sofria-render-json/schema/paragraphs.ts create mode 100644 src/lib/components/sofria-render-json/schema/sofria-schema.ts create mode 100644 src/lib/components/sofria-render-json/schema/wrappers.ts diff --git a/src/lib/components/sofria-render-json/RenderContent.svelte b/src/lib/components/sofria-render-json/RenderContent.svelte new file mode 100644 index 00000000..3ea51e29 --- /dev/null +++ b/src/lib/components/sofria-render-json/RenderContent.svelte @@ -0,0 +1,20 @@ + + +{#each content as element} + {#if typeof element === 'string'} + {element} + {:else if isWrapper(element)} + + {:else} + {(onInvalidContent(element), '')} + {/if} +{/each} diff --git a/src/lib/components/sofria-render-json/RenderParagraph.svelte b/src/lib/components/sofria-render-json/RenderParagraph.svelte new file mode 100644 index 00000000..c6eb2ee9 --- /dev/null +++ b/src/lib/components/sofria-render-json/RenderParagraph.svelte @@ -0,0 +1,32 @@ + + +{#if isUsfmParagraph(paragraph)} +
+ +
+{:else if isListBlock(paragraph)} + +{:else if isOrderedListBlock(paragraph)} +
    + +
+{:else} + {(onInvalidParagraph(), '')} +{/if} diff --git a/src/lib/components/sofria-render-json/RenderSequence.svelte b/src/lib/components/sofria-render-json/RenderSequence.svelte new file mode 100644 index 00000000..f0c4f4a4 --- /dev/null +++ b/src/lib/components/sofria-render-json/RenderSequence.svelte @@ -0,0 +1,18 @@ + + +{#each sequence.blocks as block} + {#if isParagraph(block)} + + {:else} + {(onInvalidBlockType(block), '')} + {/if} +{/each} diff --git a/src/lib/components/sofria-render-json/RenderWrapper.svelte b/src/lib/components/sofria-render-json/RenderWrapper.svelte new file mode 100644 index 00000000..278adcaf --- /dev/null +++ b/src/lib/components/sofria-render-json/RenderWrapper.svelte @@ -0,0 +1,20 @@ + + +{#if isListItem(wrapper)} +
  • + isListItem + +
  • +{:else} + {(onInvalidWrapper(), '')} +{/if} diff --git a/src/lib/components/sofria-render-json/SofriaRender.svelte b/src/lib/components/sofria-render-json/SofriaRender.svelte new file mode 100644 index 00000000..cded17d8 --- /dev/null +++ b/src/lib/components/sofria-render-json/SofriaRender.svelte @@ -0,0 +1,19 @@ + + + diff --git a/src/lib/components/sofria-render-json/schema/paragraphs.ts b/src/lib/components/sofria-render-json/schema/paragraphs.ts new file mode 100644 index 00000000..049f1b63 --- /dev/null +++ b/src/lib/components/sofria-render-json/schema/paragraphs.ts @@ -0,0 +1,28 @@ +import type { Paragraph } from './sofria-schema'; + +export function isUsfmParagraph(paragraph: Paragraph) { + return paragraph.subtype.split(':')[0] === 'usfm'; +} + +export function usfmClass(paragraph: Paragraph) { + return paragraph.subtype.split(':')[1]; +} + +export interface ListBlock extends Paragraph { + subtype: 'list_block'; +} + +export function isListBlock(block: Paragraph): block is ListBlock { + return block.subtype === 'list_block'; +} + +export interface OrderedListBlock extends Paragraph { + subtype: 'ordered_list_block'; + atts: { + start: string; + }; +} + +export function isOrderedListBlock(block: Paragraph): block is OrderedListBlock { + return block.subtype === 'ordered_list_block'; +} diff --git a/src/lib/components/sofria-render-json/schema/sofria-schema.ts b/src/lib/components/sofria-render-json/schema/sofria-schema.ts new file mode 100644 index 00000000..22f046ec --- /dev/null +++ b/src/lib/components/sofria-render-json/schema/sofria-schema.ts @@ -0,0 +1,106 @@ +// Interfaces defining the standard schema for Sofria +// Based on documentation from the proskomma-json-tools package + +export interface Document { + schema: Schema; + metadata: object; +} + +export interface FlatDocument extends Document { + sequences: { [id: string]: Sequence }; + main_sequence_id: string; +} + +export interface NestedDocument extends Document { + sequence: Sequence; +} + +export function isFlatDocument(doc: Document): doc is FlatDocument { + return doc.schema.structure === 'flat'; +} + +export function isNestedDocument(doc: Document): doc is NestedDocument { + return doc.schema.structure === 'nested'; +} + +export interface Schema { + structure: 'flat' | 'nested'; + structure_version: string; + constraints: { + name: 'perf' | 'sofria'; + version: string; + }; +} + +export interface Sequence { + type: string; + preview_text?: string; + blocks: Block[]; +} + +export interface Block { + type: 'paragraph' | 'graft'; +} + +export interface Paragraph extends Block { + type: 'paragraph'; + subtype: string; + atts: Attributes; + content: Content; +} + +export function isParagraph(block: Block): block is Paragraph { + return block.type === 'paragraph'; +} + +export interface Graft extends Block { + type: 'graft'; + new: false; + + // One of the following must be defined + target?: string; // The ID of the sequence containing the graft content + sequence?: Sequence; // The sequence containing the graft content + + preview_text?: string; + atts?: Attributes; + content: Content; +} + +export interface NewGraft extends Block { + type: 'graft'; + new: true; + + // One of the following must be defined + subtype?: string; + sequence?: Sequence; + + atts?: Attributes; +} + +export interface ContentElement { + type: 'mark' | 'wrapper' | 'start_milestone' | 'end_milestone' | 'graft'; + subtype?: string; + atts?: Attributes; + content?: Content; + meta_content?: Content; +} + +export interface Wrapper extends ContentElement { + type: 'wrapper'; + content: Content; +} + +export function isWrapper(element: ContentElement): element is Wrapper { + return element.type === 'wrapper'; +} + +export interface InlineGraft extends ContentElement { + type: 'graft'; + target?: string; + sequence?: Sequence; + preview_text?: string; + new?: boolean; +} + +export type Attributes = { [name: string]: boolean | string | string[] }; +export type Content = (string | ContentElement)[]; diff --git a/src/lib/components/sofria-render-json/schema/wrappers.ts b/src/lib/components/sofria-render-json/schema/wrappers.ts new file mode 100644 index 00000000..efa6f1ec --- /dev/null +++ b/src/lib/components/sofria-render-json/schema/wrappers.ts @@ -0,0 +1,12 @@ +import type { Wrapper } from './sofria-schema'; + +export interface ListItem extends Wrapper { + subtype: 'list_item_wrapper'; + atts: { + htmlClass: string; + }; +} + +export function isListItem(wrapper: Wrapper): wrapper is ListItem { + return wrapper.subtype === 'list_item_wrapper'; +}