Skip to content

Commit 78df163

Browse files
committed
Add interlinearizer feature with XML parsing and web view integration
- Introduced `interlinearizer.web-view.tsx` and `interlinearizer.web-view.scss` for rendering interlinear data. - Implemented `InterlinearXmlParser` for parsing interlinear XML data. - Updated `package.json` and `package-lock.json` to include `fast-xml-parser` dependency. - Added new types for interlinear data in `paranext-extension-template.d.ts`. - Included sample interlinear XML data in `test-data/Interlinear_en_MAT.xml`. - Enhanced `main.ts` to register the new web view provider for the interlinearizer. - Updated `cspell.json` with new terms related to interlinearization.
1 parent e7c53ea commit 78df163

9 files changed

Lines changed: 1119 additions & 796 deletions

cspell.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
"guids",
2525
"hopkinson",
2626
"iframes",
27+
"interlinearization",
28+
"interlinearizer",
2729
"localstorage",
2830
"maximizable",
2931
"networkable",

package-lock.json

Lines changed: 251 additions & 789 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
},
3636
"dependencies": {
3737
"@sillsdev/scripture": "^2.0.2",
38+
"fast-xml-parser": "^5.3.3",
3839
"platform-bible-utils": "file:../paranext-core/lib/platform-bible-utils"
3940
},
4041
"devDependencies": {

src/interlinearizer.web-view.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@use 'tailwind';

src/interlinearizer.web-view.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { useMemo } from 'react';
2+
import type { InterlinearData } from 'paranext-extension-template';
3+
import { InterlinearXmlParser } from './parsers/interlinearXmlParser';
4+
5+
/** Test interlinear XML bundled at build time (from test-data/Interlinear_en_MAT.xml). */
6+
import testXml from '../test-data/Interlinear_en_MAT.xml?raw';
7+
8+
const parser = new InterlinearXmlParser();
9+
10+
/** Result of parsing the bundled test XML: either data or an error message. */
11+
type ParseResult = { data: InterlinearData; error: undefined } | { data: undefined; error: string };
12+
13+
/**
14+
* Main interlinearizer WebView. Parses the bundled test XML into the interlinear model and displays
15+
* the result as raw JSON. No PAPI commands or file loading—everything is self-contained.
16+
*/
17+
globalThis.webViewComponent = function InterlinearizerWebView() {
18+
const { data: parsed, error: parseError } = useMemo((): ParseResult => {
19+
try {
20+
const data = parser.parse(testXml);
21+
return { data, error: undefined };
22+
} catch (err) {
23+
return {
24+
data: undefined,
25+
error: err instanceof Error ? err.message : String(err),
26+
};
27+
}
28+
}, []);
29+
30+
return (
31+
<div className="tw-flex tw-flex-col tw-gap-4 tw-p-6">
32+
<h1 className="tw-text-2xl tw-font-semibold tw-tracking-tight">Interlinearizer</h1>
33+
<p className="tw-text-sm tw-text-muted-foreground">
34+
Raw JSON of the model parsed from <code>test-data/Interlinear_en_MAT.xml</code>.
35+
</p>
36+
37+
{parseError && (
38+
<div className="tw-flex tw-flex-col tw-gap-2">
39+
<h2 className="tw-text-lg tw-font-medium tw-text-destructive">Parse error</h2>
40+
<pre className="tw-overflow-auto tw-rounded-md tw-bg-muted tw-p-4 tw-text-sm tw-text-muted-foreground">
41+
{parseError}
42+
</pre>
43+
</div>
44+
)}
45+
46+
{parsed && !parseError && (
47+
<>
48+
<p className="tw-text-sm tw-text-muted-foreground">Parsed interlinear data (JSON):</p>
49+
<pre className="tw-overflow-auto tw-rounded-md tw-border tw-border-border tw-bg-muted tw-p-4 tw-text-sm tw-font-mono tw-leading-relaxed">
50+
{JSON.stringify(parsed, undefined, 2)}
51+
</pre>
52+
</>
53+
)}
54+
</div>
55+
);
56+
};

src/main.ts

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,48 @@
1-
import { logger } from '@papi/backend';
1+
import papi, { logger } from '@papi/backend';
2+
import type {
3+
ExecutionActivationContext,
4+
IWebViewProvider,
5+
SavedWebViewDefinition,
6+
WebViewDefinition,
7+
} from '@papi/core';
8+
import interlinearizerReact from './interlinearizer.web-view?inline';
9+
import interlinearizerStyles from './interlinearizer.web-view.scss?inline';
210

3-
export async function activate() {
4-
logger.debug('Extension template is activating!');
11+
const mainWebViewType = 'paranextExtensionTemplate.interlinearizer';
12+
13+
/** WebView provider that provides the interlinearizer React WebView when Platform.Bible requests it. */
14+
const mainWebViewProvider: IWebViewProvider = {
15+
async getWebView(savedWebView: SavedWebViewDefinition): Promise<WebViewDefinition | undefined> {
16+
if (savedWebView.webViewType !== mainWebViewType) {
17+
throw new Error(
18+
`${mainWebViewType} provider received request to provide a ${savedWebView.webViewType} WebView`,
19+
);
20+
}
21+
return {
22+
...savedWebView,
23+
title: 'Interlinearizer',
24+
content: interlinearizerReact,
25+
styles: interlinearizerStyles,
26+
};
27+
},
28+
};
29+
30+
export async function activate(context: ExecutionActivationContext): Promise<void> {
31+
logger.debug('Interlinearizer extension is activating!');
32+
33+
const mainWebViewProviderPromise = papi.webViewProviders.registerWebViewProvider(
34+
mainWebViewType,
35+
mainWebViewProvider,
36+
);
37+
38+
papi.webViews.openWebView(mainWebViewType, undefined, { existingId: '?' });
39+
40+
context.registrations.add(await mainWebViewProviderPromise);
41+
42+
logger.debug('Interlinearizer extension finished activating!');
543
}
644

7-
export async function deactivate() {
8-
logger.debug('Extension template is deactivating!');
45+
export async function deactivate(): Promise<boolean> {
46+
logger.debug('Interlinearizer extension is deactivating!');
947
return true;
1048
}

0 commit comments

Comments
 (0)