-
-
Notifications
You must be signed in to change notification settings - Fork 0
Add USJ book parsing pipeline and interlinearizer display WebView #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
951a783
Add USJ book parsing pipeline and interlinearizer display WebView
alex-rawlings-yyc 2392764
Fix lint error
alex-rawlings-yyc a2e7552
Add div for BookChapterControl, display entire chapters at once
alex-rawlings-yyc c58467f
Fix USJ chapter/verse traversal, surrogate-pair tokenization, and mem…
alex-rawlings-yyc 45fed16
Fix tokenizer edge cases, para double-space, and stableStringify loca…
alex-rawlings-yyc df0cc4c
Fix mock function signatures, remove orphaned mocks
alex-rawlings-yyc a590bde
Fix useMemo deps, improve error logging, and clarify test/doc wording
alex-rawlings-yyc 1c13ef1
Improve error display, heading-para skipping, and test/code tidying
alex-rawlings-yyc 2076fd8
Fix correctness bugs and tighten tests from code review
alex-rawlings-yyc 37e78bf
Fix stableStringify undefined handling and add test
alex-rawlings-yyc 2dc4e72
Documentation/Error type audit
alex-rawlings-yyc b12f00f
Clean-up incomplete changes (#32)
imnasnainaec 5598f71
Fix CodeRabbit nitpicks
alex-rawlings-yyc 1f4cde5
Fix nitpicks, revert previous nitpick
alex-rawlings-yyc 2024a89
Improve docstring coverage
alex-rawlings-yyc 5e69344
Fix div-in-button issue, reintroduce export for backend mock to ensur…
alex-rawlings-yyc e5ed09c
Improve parsing of index and length in pt9 XML Parser, reject duplica…
alex-rawlings-yyc 46ab515
Tighten range/index validation to exclude non-whole numbers
alex-rawlings-yyc 477ec4f
Add TabToolbar to WebView, audit mocks
alex-rawlings-yyc dc4d30d
Improve error logging, assert writing system fallback test, improve mock
alex-rawlings-yyc 55716a1
Fix WebView registration command result schema, improved description …
alex-rawlings-yyc 8c5d31b
Addressing Danny's notes
alex-rawlings-yyc accb3d8
Addressing CR nitpicks
alex-rawlings-yyc 4c7bb09
Improve token regexes, minor adjustments, add docstring to `parseStri…
alex-rawlings-yyc da05e57
Improve `parseStrictNumber()`, improve hook mock in `papi-frontend-re…
alex-rawlings-yyc 5fc175c
Expand coverage collection to all source files
alex-rawlings-yyc c6d91cb
Clean up regex (#34)
imnasnainaec f391011
Clarify `SyntaxError` when `Range` from `Cluster` is invalid, improve…
alex-rawlings-yyc 494d322
Revert `openInterlinearizerForWebView`, as Platform.Bible has a proje…
alex-rawlings-yyc 2aff42b
Allow word-final apostrophe glottal markers to be captured
alex-rawlings-yyc 13acc79
Update comment
alex-rawlings-yyc 503883c
Tweak tests
imnasnainaec File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,63 +1,70 @@ | ||
| /** | ||
| * @file Jest mock for @papi/frontend/react. Provides stub implementations of various PAPI React hooks so | ||
| * @file Jest mock for @papi/frontend/react. Provides stub implementations of PAPI React hooks so | ||
| * WebView/frontend components can be unit-tested without the real Platform API. | ||
| */ | ||
|
|
||
| /** | ||
| * useData('providerName') returns an object whose keys are data type names and values are hooks. | ||
| * Mock: any property returns a function that returns [undefined, setter, false]. | ||
| * Mock for `useProjectData`. Returns a `Proxy` whose property accesses each yield a function | ||
| * returning `[undefined, jest.fn(), false]`, matching the real hook's `[data, setter, isLoading]` | ||
| * tuple without requiring a live data provider. | ||
| */ | ||
| const createUseDataLikeHook = () => | ||
| jest.fn(() => | ||
| new Proxy( | ||
| {}, | ||
| { | ||
| get: () => () => [undefined, jest.fn(), false], | ||
| }, | ||
| ), | ||
| ); | ||
| const useProjectData = jest.fn(() => | ||
| new Proxy( | ||
| {}, | ||
| { | ||
| get: () => () => [undefined, jest.fn(), false], | ||
| }, | ||
| ), | ||
| ); | ||
|
|
||
| const useDataProvider = jest.fn().mockReturnValue(undefined); | ||
| const useData = createUseDataLikeHook(); | ||
| const useScrollGroupScrRef = jest.fn().mockReturnValue([undefined, jest.fn()]); | ||
| const useSetting = jest.fn().mockImplementation((_key: string, defaultState: unknown) => [defaultState, jest.fn()]); | ||
| const useProjectData = createUseDataLikeHook(); | ||
| const useProjectDataProvider = jest.fn().mockReturnValue(undefined); | ||
| /** | ||
| * Mock for `useProjectSetting`. Returns `[defaultState, setSetting, resetSetting, isLoading]`, | ||
| * passing `defaultState` through unchanged so callers receive a predictable initial value. | ||
| * | ||
| * @param _projectDataProviderSource - Ignored project data provider source. | ||
| * @param _key - Ignored setting key. | ||
| * @param defaultState - Value surfaced as the current setting state. | ||
| * @returns Tuple of `[defaultState, jest.fn(), jest.fn(), false]`. | ||
| */ | ||
| const useProjectSetting = jest | ||
| .fn() | ||
| .mockImplementation((_projectInterface: string, _projectIdOrPdp: unknown, _key: string, defaultState: unknown) => [ | ||
| .mockImplementation((_projectDataProviderSource: unknown, _key: string, defaultState: unknown) => [ | ||
| defaultState, | ||
| jest.fn(), | ||
| jest.fn(), | ||
| false, | ||
| ]); | ||
| const useDialogCallback = jest.fn().mockReturnValue(jest.fn()); | ||
| const useDataProviderMulti = jest.fn().mockReturnValue([]); | ||
| /** Returns a map of localization key -> key (so tests get a string for each key). */ | ||
| const useLocalizedStrings = jest.fn().mockImplementation((keys: string[]) => | ||
| Array.isArray(keys) ? keys.reduce<Record<string, string>>((acc, k) => ({ ...acc, [k]: k }), {}) : {}, | ||
| ); | ||
| const useWebViewController = jest.fn().mockReturnValue(undefined); | ||
| const useRecentScriptureRefs = jest.fn().mockReturnValue([]); | ||
|
|
||
| /** | ||
| * Mock for `useLocalizedStrings`. Maps each requested key to itself so tests receive a | ||
| * predictable `Record<string, string>` without a real localization service. | ||
| * | ||
| * @param keys - BCP47-style string keys to resolve. | ||
| * @returns Tuple of `[record, isLoading]` where every key maps to itself and `isLoading` is | ||
| * `false`. | ||
| */ | ||
| const useLocalizedStrings = jest.fn().mockImplementation((keys: string[]) => [ | ||
| Array.isArray(keys) ? keys.reduce<Record<string, string>>((acc, k) => { acc[k] = k; return acc; }, {}) : {}, | ||
| false, | ||
| ]); | ||
|
|
||
| /** | ||
| * Mock for `useRecentScriptureRefs`. Returns an empty history and a no-op `addRecentScriptureRef` | ||
| * so components that display recent references render without errors. | ||
| * | ||
| * @returns Object with `recentScriptureRefs` (empty array) and `addRecentScriptureRef` (jest spy). | ||
| */ | ||
| const useRecentScriptureRefs = jest | ||
| .fn() | ||
| .mockImplementation(() => ({ recentScriptureRefs: [], addRecentScriptureRef: jest.fn() })); | ||
|
|
||
| module.exports = { | ||
| __esModule: true, | ||
| useDataProvider, | ||
| useData, | ||
| useScrollGroupScrRef, | ||
| useSetting, | ||
| useProjectData, | ||
| useProjectDataProvider, | ||
| useProjectSetting, | ||
| useDialogCallback, | ||
| useDataProviderMulti, | ||
| useLocalizedStrings, | ||
| useWebViewController, | ||
| useRecentScriptureRefs, | ||
| __mockUseDataProvider: useDataProvider, | ||
| __mockUseData: useData, | ||
| __mockUseLocalizedStrings: useLocalizedStrings, | ||
| __mockUseSetting: useSetting, | ||
| __mockUseProjectData: useProjectData, | ||
| __mockUseProjectDataProvider: useProjectDataProvider, | ||
| __mockUseProjectSetting: useProjectSetting, | ||
| __mockUseWebViewController: useWebViewController, | ||
| }; | ||
|
|
||
| /** Marks this file as a module so top-level const/let are module-scoped. */ | ||
| export {}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| /** | ||
| * @file Jest mock for platform-bible-react. The real package ships ESM which Jest cannot parse | ||
| * without extra transform configuration. This stub provides the subset used by extension | ||
| * components: `BookChapterControl`, `BOOK_CHAPTER_CONTROL_STRING_KEYS`, `TabToolbar`, and | ||
| * `ScrollGroupSelector`. | ||
| */ | ||
|
|
||
| import type { ReactElement, ReactNode } from 'react'; | ||
|
|
||
| interface SerializedVerseRef { | ||
| book: string; | ||
| chapterNum: number; | ||
| verseNum: number; | ||
| verse?: string; | ||
| versificationStr?: string; | ||
| } | ||
|
|
||
| export const BOOK_CHAPTER_CONTROL_STRING_KEYS: string[] = []; | ||
|
|
||
| export function TabToolbar({ | ||
| startAreaChildren, | ||
| endAreaChildren, | ||
| }: Readonly<{ | ||
| className?: string; | ||
| startAreaChildren?: ReactNode; | ||
| endAreaChildren?: ReactNode; | ||
| onSelectProjectMenuItem?: () => void; | ||
| onSelectViewInfoMenuItem?: () => void; | ||
| }>): ReactElement { | ||
| return ( | ||
| <div data-testid="tab-toolbar"> | ||
| <div data-testid="tab-toolbar-start">{startAreaChildren}</div> | ||
| <div data-testid="tab-toolbar-end">{endAreaChildren}</div> | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| export function ScrollGroupSelector({ | ||
| availableScrollGroupIds, | ||
| scrollGroupId, | ||
| onChangeScrollGroupId, | ||
| }: Readonly<{ | ||
| availableScrollGroupIds?: (number | undefined)[]; | ||
| scrollGroupId?: number; | ||
| onChangeScrollGroupId?: (id: number | undefined) => void; | ||
| }>): ReactElement { | ||
| return ( | ||
| <select | ||
| data-testid="scroll-group-selector" | ||
| value={scrollGroupId ?? ''} | ||
| onChange={(e) => onChangeScrollGroupId?.(e.target.value === '' ? undefined : Number(e.target.value))} | ||
| > | ||
| <option value="">—</option> | ||
| {availableScrollGroupIds?.map((id) => ( | ||
| <option key={id ?? 'undefined'} value={id ?? ''}> | ||
| {id ?? '—'} | ||
| </option> | ||
| ))} | ||
| </select> | ||
| ); | ||
| } | ||
|
|
||
| export function BookChapterControl({ | ||
| scrRef, | ||
| handleSubmit, | ||
| onAddRecentSearch, | ||
| }: Readonly<{ | ||
| scrRef: SerializedVerseRef; | ||
| handleSubmit: (ref: SerializedVerseRef) => void; | ||
| className?: string; | ||
| localizedStrings?: Record<string, string>; | ||
| recentSearches?: SerializedVerseRef[]; | ||
| onAddRecentSearch?: (scrRef: SerializedVerseRef) => void; | ||
| id?: string; | ||
| }>): ReactElement { | ||
| return ( | ||
| <div data-testid="book-chapter-control"> | ||
| {scrRef.book} {scrRef.chapterNum}:{scrRef.verseNum} | ||
| <button type="button" onClick={() => {handleSubmit(scrRef); onAddRecentSearch?.(scrRef);}}> | ||
| Submit reference | ||
| </button> | ||
| </div> | ||
| ); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.