Skip to content

Commit

Permalink
Create sofria json render engine
Browse files Browse the repository at this point in the history
  • Loading branch information
gmjgeek committed Jul 29, 2024
1 parent 86804d1 commit 3716c62
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/lib/components/sofria-render-json/RenderContent.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script lang="ts">
import RenderWrapper from './RenderWrapper.svelte';
import { Content, ContentElement, isWrapper } from './schema/sofria-schema';
export let content: Content;
function onInvalidContent(element: ContentElement) {
console.error(`Unsupported content type: ${element.type}`);
}
</script>

{#each content as element}
{#if typeof element === 'string'}
{element}
{:else if isWrapper(element)}
<RenderWrapper wrapper={element} />
{:else}
{(onInvalidContent(element), '')}
{/if}
{/each}
32 changes: 32 additions & 0 deletions src/lib/components/sofria-render-json/RenderParagraph.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script lang="ts">
import {
isListBlock,
isOrderedListBlock,
isUsfmParagraph,
usfmClass
} from './schema/paragraphs';
import RenderContent from './RenderContent.svelte';
import { Paragraph } from './schema/sofria-schema';
export let paragraph: Paragraph;
function onInvalidParagraph() {
console.error(`Unsupported paragraph type: ${paragraph.subtype}`);
}
</script>

{#if isUsfmParagraph(paragraph)}
<div class={usfmClass(paragraph)}>
<RenderContent content={paragraph.content} />
</div>
{:else if isListBlock(paragraph)}
<ul>
<RenderContent content={paragraph.content} />
</ul>
{:else if isOrderedListBlock(paragraph)}
<ol start={parseInt(paragraph.atts.start)}>
<RenderContent content={paragraph.content} />
</ol>
{:else}
{(onInvalidParagraph(), '')}
{/if}
18 changes: 18 additions & 0 deletions src/lib/components/sofria-render-json/RenderSequence.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script lang="ts">
import RenderParagraph from './RenderParagraph.svelte';
import { Block, isParagraph, Sequence } from './schema/sofria-schema';
export let sequence: Sequence;
function onInvalidBlockType(block: Block) {
console.error(`Unsupported block type: ${block.type}`);
}
</script>

{#each sequence.blocks as block}
{#if isParagraph(block)}
<RenderParagraph paragraph={block} />
{:else}
{(onInvalidBlockType(block), '')}
{/if}
{/each}
20 changes: 20 additions & 0 deletions src/lib/components/sofria-render-json/RenderWrapper.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script lang="ts">
import RenderContent from './RenderContent.svelte';
import { Wrapper } from './schema/sofria-schema';
import { isListItem } from './schema/wrappers';
export let wrapper: Wrapper;
function onInvalidWrapper() {
console.warn(`Unsupported wrapper type: ${wrapper.type}`);
}
</script>

{#if isListItem(wrapper)}
<li class={wrapper.atts.htmlClass}>
isListItem
<RenderContent content={wrapper.content} />
</li>
{:else}
{(onInvalidWrapper(), '')}
{/if}
19 changes: 19 additions & 0 deletions src/lib/components/sofria-render-json/SofriaRender.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script lang="ts">
import { sequence } from '@sveltejs/kit/hooks';
import RenderSequence from './RenderSequence.svelte';
import { Document, isFlatDocument, isNestedDocument, Sequence } from './schema/sofria-schema';
export let document: Document;
let mainSequence: Sequence;
if (isFlatDocument(document)) {
mainSequence = document.sequences[document.main_sequence_id];
} else if (isNestedDocument(document)) {
mainSequence = document.sequence;
} else {
throw new Error(`Unsupported document structure: ${document.schema.structure}`);
}
</script>

<RenderSequence sequence={mainSequence} />
28 changes: 28 additions & 0 deletions src/lib/components/sofria-render-json/schema/paragraphs.ts
Original file line number Diff line number Diff line change
@@ -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';
}
106 changes: 106 additions & 0 deletions src/lib/components/sofria-render-json/schema/sofria-schema.ts
Original file line number Diff line number Diff line change
@@ -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)[];
12 changes: 12 additions & 0 deletions src/lib/components/sofria-render-json/schema/wrappers.ts
Original file line number Diff line number Diff line change
@@ -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';
}

0 comments on commit 3716c62

Please sign in to comment.