From 666f74f2b0046493efcac1940a1fc0080f2d3fb8 Mon Sep 17 00:00:00 2001 From: tjcouch-sil Date: Fri, 6 Oct 2023 15:23:06 -0500 Subject: [PATCH 1/2] Reworked ParatextStandard PDP to include USFM in data type names, wrote TypeScript types for potential Scripture and Project Note data --- .../Projects/ParatextProjectDataProvider.cs | 24 +- .../ParatextProjectStorageInterpreter.cs | 20 +- .../project-notes-data-provider/index.d.ts | 221 ++++++++++++ .../project-notes-data-provider/manifest.json | 9 + extensions/src/usfm-data-provider/index.d.ts | 327 +++++++++++++++++- lib/papi-dts/papi.d.ts | 8 - src/declarations/papi-shared-types.ts | 9 - src/main/main.ts | 8 +- 8 files changed, 581 insertions(+), 45 deletions(-) create mode 100644 extensions/src/project-notes-data-provider/index.d.ts create mode 100644 extensions/src/project-notes-data-provider/manifest.json diff --git a/c-sharp/Projects/ParatextProjectDataProvider.cs b/c-sharp/Projects/ParatextProjectDataProvider.cs index 3cdba7bdd8..a50335e4e2 100644 --- a/c-sharp/Projects/ParatextProjectDataProvider.cs +++ b/c-sharp/Projects/ParatextProjectDataProvider.cs @@ -16,10 +16,10 @@ ProjectDetails projectDetails : base(name, papiClient, projectDetails) { _paratextPsi = paratextPsi; - Getters.Add("getBook", GetBook); - Getters.Add("getChapter", GetChapter); - Setters.Add("setChapter", SetChapter); - Getters.Add("getVerse", GetVerse); + Getters.Add("getBookUSFM", GetBookUSFM); + Getters.Add("getChapterUSFM", GetChapterUSFM); + Setters.Add("setChapterUSFM", SetChapterUSFM); + Getters.Add("getVerseUSFM", GetVerseUSFM); } protected override Task StartDataProvider() @@ -61,23 +61,23 @@ private ResponseToRequest Set(string dataType, string dataQualifier, string data return _paratextPsi.SetProjectData(scope, data); } - private ResponseToRequest GetBook(string jsonString) + private ResponseToRequest GetBookUSFM(string jsonString) { - return Get(ParatextProjectStorageInterpreter.Book, jsonString); + return Get(ParatextProjectStorageInterpreter.BookUSFM, jsonString); } - private ResponseToRequest GetChapter(string jsonString) + private ResponseToRequest GetChapterUSFM(string jsonString) { - return Get(ParatextProjectStorageInterpreter.Chapter, jsonString); + return Get(ParatextProjectStorageInterpreter.ChapterUSFM, jsonString); } - private ResponseToRequest GetVerse(string jsonString) + private ResponseToRequest GetVerseUSFM(string jsonString) { - return Get(ParatextProjectStorageInterpreter.Verse, jsonString); + return Get(ParatextProjectStorageInterpreter.VerseUSFM, jsonString); } - private ResponseToRequest SetChapter(string dataQualifier, string data) + private ResponseToRequest SetChapterUSFM(string dataQualifier, string data) { - return Set(ParatextProjectStorageInterpreter.Chapter, dataQualifier, data); + return Set(ParatextProjectStorageInterpreter.ChapterUSFM, dataQualifier, data); } } diff --git a/c-sharp/Projects/ParatextProjectStorageInterpreter.cs b/c-sharp/Projects/ParatextProjectStorageInterpreter.cs index ce6a064851..07a7204e06 100644 --- a/c-sharp/Projects/ParatextProjectStorageInterpreter.cs +++ b/c-sharp/Projects/ParatextProjectStorageInterpreter.cs @@ -9,9 +9,9 @@ namespace Paranext.DataProvider.Projects; internal class ParatextProjectStorageInterpreter : ProjectStorageInterpreter { - public const string Book = "BOOK"; - public const string Chapter = "CHAPTER"; - public const string Verse = "VERSE"; + public const string BookUSFM = "BookUSFM"; + public const string ChapterUSFM = "ChapterUSFM"; + public const string VerseUSFM = "VerseUSFM"; public ParatextProjectStorageInterpreter(PapiClient papiClient) : base(ProjectStorageType.ParatextFolders, new[] { ProjectType.Paratext }, papiClient) { } @@ -84,17 +84,17 @@ public override ResponseToRequest GetProjectData(ProjectDataScope scope) VerseRefConverter.TryCreateVerseRef(scope.DataQualifier, out var verseRef, out var error); var scrText = LocalProjects.GetParatextProject(scope.ProjectID); - return scope.DataType.ToUpperInvariant() switch + return scope.DataType switch { - Book + BookUSFM => string.IsNullOrEmpty(error) ? ResponseToRequest.Succeeded(scrText.GetText(verseRef, false, false)) : ResponseToRequest.Failed(error), - Chapter + ChapterUSFM => string.IsNullOrEmpty(error) ? ResponseToRequest.Succeeded(scrText.GetText(verseRef, true, false)) : ResponseToRequest.Failed(error), - Verse + VerseUSFM => string.IsNullOrEmpty(error) ? ResponseToRequest.Succeeded(scrText.Parser.GetVerseUsfmText(verseRef)) : ResponseToRequest.Failed(error), @@ -115,9 +115,9 @@ public override ResponseToRequest SetProjectData(ProjectDataScope scope, string VerseRefConverter.TryCreateVerseRef(scope.DataQualifier, out var verseRef, out var error); var scrText = LocalProjects.GetParatextProject(scope.ProjectID); - switch (scope.DataType.ToUpperInvariant()) + switch (scope.DataType) { - case Chapter: + case ChapterUSFM: if (!string.IsNullOrEmpty(error)) return ResponseToRequest.Failed(error); RunWithinLock( @@ -134,7 +134,7 @@ public override ResponseToRequest SetProjectData(ProjectDataScope scope, string } ); // The value of returned string is case sensitive and cannot change unless data provider subscriptions change - return ResponseToRequest.Succeeded("Chapter"); + return ResponseToRequest.Succeeded(ChapterUSFM); default: return ResponseToRequest.Failed($"Unknown data type: {scope.DataType}"); } diff --git a/extensions/src/project-notes-data-provider/index.d.ts b/extensions/src/project-notes-data-provider/index.d.ts new file mode 100644 index 0000000000..c10617b7d8 --- /dev/null +++ b/extensions/src/project-notes-data-provider/index.d.ts @@ -0,0 +1,221 @@ +import { VerseRef } from '@sillsdev/scripture'; +import type { + DataProviderDataType, + DataProviderSubscriberOptions, +} from 'shared/models/data-provider.model'; +import type IDataProvider from 'shared/models/data-provider.interface'; +import type { PapiEvent } from 'shared/models/papi-event.model'; +import type { Unsubscriber } from 'shared/utils/papi-util'; + +declare module 'project-notes-data-provider' { + export type ProjectNotesProviderDataTypes = { + /** Get notes from the provider. `setNotes` is not available; please use `addNote` */ + Notes: DataProviderDataType; + }; + + /** Data provider for manipulating project notes */ + export type ProjectNotesDataProvider = IDataProvider & { + /** + * Adds a project note + * + * @param anchor A selection in the Scripture text representing the "anchor" location of the note. Note that the `ScriptureTextSelection.SelectedText` is expected to begin and end at a word break; We will attempt to expand the selection if it is not. + * @param contentParagraphs One or more paragraphs of formatted text + * @param language The default language used in `contentParagraphs` (except where specified explicitly in a `FormattedString`). + * @param assignedUser User (if any) to whom the new note is to be assigned. + * + * @returns `ProjectNote` the newly added note + */ + addNote( + anchor: ScriptureTextSelection, + contentParagraphs: CommentParagraph[], + language?: Language, + assignedUser?: UserInfo, + ): Promise; + }; + + /** An object representing a project note */ + type ProjectNote = { + /** A selection in the Scripture text representing the "anchor" location of the note. */ + anchor: ScriptureTextSelection; + /** Present in a note when it has been assigned to a particular user. */ + assignedUser?: UserInfo; + /** The comments that comprise the note */ + comments: Comment[]; + /** Flag indicating whether all the comments of the note have been read by the current user. */ + isRead: boolean; + /** Flag indicating whether this note is resolved. */ + isResolved: boolean; + /** Present in a note when it has been assigned to reply-to a particular user. */ + replyToUser?: UserInfo; + }; + + /** A selection in the Scripture text */ + type ScriptureTextSelection = { + /** The raw USFM text following the SelectedText (typically the remainder of the verse represented by VerseRefEnd). */ + afterContext: string; + /** The raw USFM text preceding the SelectedText (typically the entirety of the verse represented by VerseRefStart up to Offset). */ + beforeContext: string; + /** The character offset (in the raw USFM data) starting from the point before the \v (i.e., the slash is the 0th character). */ + offset: number; + /** The selected text represented by this object. Can be an empty string (representing an insertion point). */ + selectedText: string; + /** The verse where the selection ends. */ + verseRefEnd: VerseRef; + /** The verse where the selection starts. */ + verseRefStart: VerseRef; + }; + + /** An object representing information about a user */ + type UserInfo = { + /** Gets the registration name of the current user or an empty string if there is no registration information */ + name: string; + }; + + /** An object representing a comment in a project note */ + type Comment = { + /** User to whom a comment is/was assigned. */ + assignedUser?: UserInfo; + /** User who authored this comment */ + author: UserInfo; + /** The list of paragraphs making up the contents of this comment. */ + contents: CommentParagraph[]; + /** Date/time this comment was created */ + created: Date; + /** The language used in the comment (except where specified explicitly in a FormattedString). */ + language?: Language; + }; + + /** + * An object representing a language definition + * + * WARNING: SUBJECT TO CHANGE + */ + type Language = { + /** Gets the default font. */ + font?: Font; + /** Gets the IETF BCP-47 language tag. */ + id: string; + /** Gets whether the language is displayed right-to-left. */ + isRtoL: boolean; + }; + + /** + * Object representing a font + * + * WARNING: SUBJECT TO CHANGE + */ + type Font = { + /** A comma-separated list of selected feature options for a Graphite font. REVIEW: Although Paratext does not seem to support selection of features for Open Type fonts, it's possible that existing LDML files may have this information and it could be used by Paratext (and therefore maybe passed on here). */ + features?: string; + /** Name of the font family, which represents a group of fonts that have a similar font face. */ + fontFamily?: string; + /** The language tag needed to tell a Graphite font which set of customized rules to use. */ + language?: string; + /** The em-size measured in in points */ + size?: number; + }; + + /** + * Object representing a paragraph in a comment + * + * WARNING: SUBJECT TO CHANGE DEPENDING ON HOW WE WANT TO MAKE RICH TEXT EDITING + */ + type CommentParagraph = { + /** List of formatted text spans that make up the paragraph */ + spans: FormattedString[]; + }; + + /** + * A span of text that has formatting specified + * + * WARNING: SUBJECT TO CHANGE DEPENDING ON HOW WE WANT TO MAKE RICH TEXT EDITING + */ + type FormattedString = { + /** The language in which the text is written. If null, the language is the Comment.Language of the owning comment. */ + language?: Language; + /** Flags indicating the style */ + style: Style; + /** The text of the string. Cannot be null or empty. */ + text: string; + }; + + /** + * Indicates which styles are applied on a FormattedString. + * + * WARNING: SUBJECT TO CHANGE DEPENDING ON HOW WE WANT TO MAKE RICH TEXT EDITING + */ + enum Style { + /** Includes bold formatting */ + Bold = 0, + /** Includes italics formatting */ + Italic = 1, + /** No special formatting */ + Plain = 2, + } + + /** Specifies which notes to retrieve from `ProjectNotesDataProvider.GetNotes` */ + type ProjectNotesSelector = { + /** The project from which to get notes */ + projectId: string; + /** + * Book number from which to retrieve notes. If not provided or 0, get notes from the entire project + * + * @default 0 + */ + bookNum?: number; + /** + * Chapter number from which to retrieve notes. If not provided or 0, get notes from the whole book + * + * @default 0 + */ + chapterNum?: number; + /** + * Whether or not to return only unresolved notes. + * + * @default false + */ + shouldRetrieveOnlyUnresolved?: boolean; + }; + + /** + * Data provider for manipulating project notes + * + * This is a hand-written baked-out version of `ProjectNotesDataProvider` for ease of reading + */ + type ProjectNotesDataProviderExpanded = { + /** Event emitted when this provider is disposed */ + onDidDispose: PapiEvent; + /** Get notes from the provider. `setNotes` is not available; please use `addNote` */ + getNotes(notesSelector: ProjectNotesSelector): Promise; + /** + * Subscribe to run a callback function when notes are added + * + * @param notesSelector tells the provider what notes to listen for + * @param callback function to run with the updated notes for this selector + * @param options various options to adjust how the subscriber emits updates + * + * @returns unsubscriber function (run to unsubscribe from listening for updates) + */ + subscribeNotes( + notesSelector: ProjectNotesSelector, + callback: (notes: ProjectNote[]) => void, + options?: DataProviderSubscriberOptions, + ): Unsubscriber; + /** + * Adds a project note + * + * @param anchor A selection in the Scripture text representing the "anchor" location of the note. Note that the `ScriptureTextSelection.SelectedText` is expected to begin and end at a word break; We will attempt to expand the selection if it is not. + * @param contentParagraphs One or more paragraphs of formatted text + * @param language The default language used in `contentParagraphs` (except where specified explicitly in a `FormattedString`). + * @param assignedUser User (if any) to whom the new note is to be assigned. + * + * @returns `ProjectNote` the newly added note + */ + addNote( + anchor: ScriptureTextSelection, + contentParagraphs: CommentParagraph[], + language?: Language, + assignedUser?: UserInfo, + ): Promise; + }; +} diff --git a/extensions/src/project-notes-data-provider/manifest.json b/extensions/src/project-notes-data-provider/manifest.json new file mode 100644 index 0000000000..7d78a540b6 --- /dev/null +++ b/extensions/src/project-notes-data-provider/manifest.json @@ -0,0 +1,9 @@ +{ + "name": "project-notes-data-provider", + "version": "0.0.1", + "description": "Project Notes Data Provider for Paranext - provided by C# data provider", + "author": "Paranext", + "license": "MIT", + "main": null, + "activationEvents": [] +} diff --git a/extensions/src/usfm-data-provider/index.d.ts b/extensions/src/usfm-data-provider/index.d.ts index e9554b7532..a522a3bf19 100644 --- a/extensions/src/usfm-data-provider/index.d.ts +++ b/extensions/src/usfm-data-provider/index.d.ts @@ -1,6 +1,15 @@ import { VerseRef } from '@sillsdev/scripture'; -import type { DataProviderDataType } from 'shared/models/data-provider.model'; +import type { + DataProviderDataType, + DataProviderSubscriberOptions, + DataProviderUpdateInstructions, +} from 'shared/models/data-provider.model'; import type IDataProvider from 'shared/models/data-provider.interface'; +import type { + ExtensionDataScope, + MandatoryProjectDataType, +} from 'shared/models/project-data-provider.model'; +import type { Unsubscriber } from 'shared/utils/papi-util'; declare module 'usfm-data-provider' { export type UsfmProviderDataTypes = { @@ -12,3 +21,319 @@ declare module 'usfm-data-provider' { export type UsfmDataProvider = IDataProvider; } + +declare module 'papi-shared-types' { + /** This is not yet a complete list of the data types available from Paratext projects. */ + export type ParatextStandardProjectDataTypes = MandatoryProjectDataType & { + /** Gets the "raw" USFM data for the specified book */ + BookUSFM: DataProviderDataType; + /** Gets the "raw" USFM data for the specified chapter */ + ChapterUSFM: DataProviderDataType; + /** Gets the "raw" USFM data for the specified verse */ + VerseUSFM: DataProviderDataType; + /** + * Gets the tokenized USJ data for the specified book + * + * WARNING: USJ is one of many possible tokenized formats that we may use, so this may change + * over time. Additionally, USJ is in very early stages of proposal, so it will likely also + * change over time. + */ + BookUSJ: DataProviderDataType; + /** + * Gets the tokenized USJ data for the specified chapter + * + * WARNING: USJ is one of many possible tokenized formats that we may use, so this may change + * over time. Additionally, USJ is in very early stages of proposal, so it will likely also + * change over time. + */ + ChapterUSJ: DataProviderDataType; + /** + * Gets the tokenized USJ data for the specified verse + * + * WARNING: USJ is one of many possible tokenized formats that we may use, so this may change + * over time. Additionally, USJ is in very early stages of proposal, so it will likely also + * change over time. + */ + VerseUSJ: DataProviderDataType; + }; + + export interface ProjectDataTypes { + ParatextStandard: ParatextStandardProjectDataTypes; + } + + /** + * Scripture data represented in JSON format. Transformation from USX + * + * [See more information here](https://github.com/paranext/paranext-core/issues/480#issuecomment-1751094148) + */ + type USJDocument = { + /** The Scripture data serialization format used for this document */ + type: 'USJ'; + /** The USJ spec version */ + version: '0.0.1-alpha.2'; + /** Scripture contents laid out in a linear fashion */ + content: MarkerContent[]; + }; + + /** One piece of Scripture content. Can be a simple string or a marker and its contents */ + type MarkerContent = string | MarkerObject; + + /** A Scripture Marker and its contents */ + type MarkerObject = { + /** + * The kind of node or element this is, corresponding to each marker in USFM or each node in USX + * + * Its format is `type:style` + * + * @example `para:p`, `verse:v`, `char:nd` + */ + type: `${string}:${string}`; + /** This marker's contents laid out in a linear fashion */ + content?: MarkerContent[]; + /** Indicates the Book-chapter-verse value in the paragraph based structure */ + sid?: string; + /** Chapter number or verse number */ + number?: string; + /** The 3-letter book code in the id element */ + code?: BookCode; + /** Alternate chapter number or verse number */ + altnumber?: string; + /** Published character of chapter or verse */ + pubnumber?: string; + /** Caller character for footnotes and cross-refs */ + caller?: string; + /** Alignment of table cells */ + align?: string; + /** Category of extended study bible sections */ + category?: string; + }; + + /** Three-letter Scripture book code */ + // prettier-ignore + type BookCode = "GEN" | "EXO" | "LEV" | "NUM" | "DEU" | "JOS" | "JDG" | "RUT" | "1SA" | "2SA" | "1KI" | "2KI" | "1CH" | "2CH" | "EZR" | "NEH" | "EST" | "JOB" | "PSA" | "PRO" | "ECC" | "SNG" | "ISA" | "JER" | "LAM" | "EZK" | "DAN" | "HOS" | "JOL" | "AMO" | "OBA" | "JON" | "MIC" | "NAM" | "HAB" | "ZEP" | "HAG" | "ZEC" | "MAL" | "MAT" | "MRK" | "LUK" | "JHN" | "ACT" | "ROM" | "1CO" | "2CO" | "GAL" | "EPH" | "PHP" | "COL" | "1TH" | "2TH" | "1TI" | "2TI" | "TIT" | "PHM" | "HEB" | "JAS" | "1PE" | "2PE" | "1JN" | "2JN" | "3JN" | "JUD" | "REV" | "TOB" | "JDT" | "ESG" | "WIS" | "SIR" | "BAR" | "LJE" | "S3Y" | "SUS" | "BEL" | "1MA" | "2MA" | "3MA" | "4MA" | "1ES" | "2ES" | "MAN" | "PS2" | "ODA" | "PSS" | "EZA" | "5EZ" | "6EZ" | "DAG" | "PS3" | "2BA" | "LBA" | "JUB" | "ENO" | "1MQ" | "2MQ" | "3MQ" | "REP" | "4BA" | "LAO" | "FRT" | "BAK" | "OTH" | "INT" | "CNC" | "GLO" | "TDX" | "NDX" | "XXA" | "XXB" | "XXC" | "XXD" | "XXE" | "XXF" | "XXG"; + + /** + * Provides project data for Paratext Scripture projects. One is created for each project that is used + * + * This is a hand-written baked-out version of `ParatextStandardProjectDataProvider` for ease of reading + */ + type ParatextStandardProjectDataProviderExpanded = { + /** Gets the "raw" USFM data for the specified book */ + getBookUSFM(verseRef: VerseRef): Promise; + /** Sets the "raw" USFM data for the specified book */ + setBookUSFM( + verseRef: VerseRef, + usfm: string, + ): Promise>; + /** + * Subscribe to run a callback function when the "raw" USFM data is changed + * + * @param verseRef tells the provider what changes to listen for + * @param callback function to run with the updated USFM for this selector + * @param options various options to adjust how the subscriber emits updates + * + * @returns unsubscriber function (run to unsubscribe from listening for updates) + */ + subscribeBookUSFM( + verseRef: VerseRef, + callback: (usfm: string | undefined) => void, + options?: DataProviderSubscriberOptions, + ): Unsubscriber; + + /** Gets the "raw" USFM data for the specified chapter */ + getChapterUSFM(verseRef: VerseRef): Promise; + /** Sets the "raw" USFM data for the specified chapter */ + setChapterUSFM( + verseRef: VerseRef, + usfm: string, + ): Promise>; + /** + * Subscribe to run a callback function when the "raw" USFM data is changed + * + * @param verseRef tells the provider what changes to listen for + * @param callback function to run with the updated USFM for this selector + * @param options various options to adjust how the subscriber emits updates + * + * @returns unsubscriber function (run to unsubscribe from listening for updates) + */ + subscribeChapterUSFM( + verseRef: VerseRef, + callback: (usfm: string | undefined) => void, + options?: DataProviderSubscriberOptions, + ): Unsubscriber; + + /** Gets the "raw" USFM data for the specified verse */ + getVerseUSFM(verseRef: VerseRef): Promise; + /** Sets the "raw" USFM data for the specified verse */ + setVerseUSFM( + verseRef: VerseRef, + usfm: string, + ): Promise>; + /** + * Subscribe to run a callback function when the "raw" USFM data is changed + * + * @param verseRef tells the provider what changes to listen for + * @param callback function to run with the updated USFM for this selector + * @param options various options to adjust how the subscriber emits updates + * + * @returns unsubscriber function (run to unsubscribe from listening for updates) + */ + subscribeVerseUSFM( + verseRef: VerseRef, + callback: (usfm: string | undefined) => void, + options?: DataProviderSubscriberOptions, + ): Unsubscriber; + + /** + * Gets the tokenized USJ data for the specified book + * + * WARNING: USJ is one of many possible tokenized formats that we may use, so this may change + * over time. Additionally, USJ is in very early stages of proposal, so it will likely also + * change over time. + */ + getBookUSJ(verseRef: VerseRef): Promise; + /** + * Sets the tokenized USJ data for the specified book + * + * WARNING: USJ is one of many possible tokenized formats that we may use, so this may change + * over time. Additionally, USJ is in very early stages of proposal, so it will likely also + * change over time. + */ + setBookUSJ( + verseRef: VerseRef, + usj: USJDocument, + ): Promise>; + /** + * Subscribe to run a callback function when the tokenized USJ data is changed + * + * WARNING: USJ is one of many possible tokenized formats that we may use, so this may change + * over time. Additionally, USJ is in very early stages of proposal, so it will likely also + * change over time. + * + * @param verseRef tells the provider what changes to listen for + * @param callback function to run with the updated USJ for this selector + * @param options various options to adjust how the subscriber emits updates + * + * @returns unsubscriber function (run to unsubscribe from listening for updates) + */ + subscribeBookUSJ( + verseRef: VerseRef, + callback: (usj: USJDocument | undefined) => void, + options?: DataProviderSubscriberOptions, + ): Unsubscriber; + + /** + * Gets the tokenized USJ data for the specified chapter + * + * WARNING: USJ is one of many possible tokenized formats that we may use, so this may change + * over time. Additionally, USJ is in very early stages of proposal, so it will likely also + * change over time. + */ + getChapterUSJ(verseRef: VerseRef): Promise; + /** + * Sets the tokenized USJ data for the specified chapter + * + * WARNING: USJ is one of many possible tokenized formats that we may use, so this may change + * over time. Additionally, USJ is in very early stages of proposal, so it will likely also + * change over time. + */ + setChapterUSJ( + verseRef: VerseRef, + usj: USJDocument, + ): Promise>; + /** + * Subscribe to run a callback function when the tokenized USJ data is changed + * + * WARNING: USJ is one of many possible tokenized formats that we may use, so this may change + * over time. Additionally, USJ is in very early stages of proposal, so it will likely also + * change over time. + * + * @param verseRef tells the provider what changes to listen for + * @param callback function to run with the updated USJ for this selector + * @param options various options to adjust how the subscriber emits updates + * + * @returns unsubscriber function (run to unsubscribe from listening for updates) + */ + subscribeChapterUSJ( + verseRef: VerseRef, + callback: (usj: USJDocument | undefined) => void, + options?: DataProviderSubscriberOptions, + ): Unsubscriber; + + /** + * Gets the tokenized USJ data for the specified verse + * + * WARNING: USJ is one of many possible tokenized formats that we may use, so this may change + * over time. Additionally, USJ is in very early stages of proposal, so it will likely also + * change over time. + */ + getVerseUSJ(verseRef: VerseRef): Promise; + /** + * Sets the tokenized USJ data for the specified verse + * + * WARNING: USJ is one of many possible tokenized formats that we may use, so this may change + * over time. Additionally, USJ is in very early stages of proposal, so it will likely also + * change over time. + */ + setVerseUSJ( + verseRef: VerseRef, + usj: USJDocument, + ): Promise>; + /** + * Subscribe to run a callback function when the tokenized USJ data is changed + * + * WARNING: USJ is one of many possible tokenized formats that we may use, so this may change + * over time. Additionally, USJ is in very early stages of proposal, so it will likely also + * change over time. + * + * @param verseRef tells the provider what changes to listen for + * @param callback function to run with the updated USJ for this selector + * @param options various options to adjust how the subscriber emits updates + * + * @returns unsubscriber function (run to unsubscribe from listening for updates) + */ + subscribeVerseUSJ( + verseRef: VerseRef, + callback: (usj: USJDocument | undefined) => void, + options?: DataProviderSubscriberOptions, + ): Unsubscriber; + + /** + * Gets an extension's serialized project data (so the extension can provide and manipulate its project data) + * + * @param dataScope contains the name of the extension requesting the data and which data it is requesting + * @example `{ extensionName: 'biblicalTerms', dataQualifier: 'renderings' }` + * + * @returns promise that resolves to the requested extension project data + */ + getExtensionData(dataScope: ExtensionDataScope): Promise; + /** + * Sets an extension's serialized project data (so the extension can provide and manipulate its project data) + * + * @param dataScope contains the name of the extension requesting the data and which data it is requesting + * @example `{ extensionName: 'biblicalTerms', dataQualifier: 'renderings' }` + * @param extensionData the new project data for this extension + * + * @returns promise that resolves indicating which data types received updates + */ + setExtensionData( + dataScope: ExtensionDataScope, + extensionData: string | undefined, + ): Promise>; + /** + * Subscribe to run a callback function when an extension's serialized project data is changed + * + * @param dataScope contains the name of the extension requesting the data and which data it is requesting + * @example `{ extensionName: 'biblicalTerms', dataQualifier: 'renderings' }` + * @param callback function to run with the updated extension data for this selector + * @param options various options to adjust how the subscriber emits updates + * + * @returns unsubscriber function (run to unsubscribe from listening for updates) + */ + subscribeExtensionData( + dataScope: ExtensionDataScope, + callback: (extensionData: string | undefined) => void, + options?: DataProviderSubscriberOptions, + ): Unsubscriber; + }; +} diff --git a/lib/papi-dts/papi.d.ts b/lib/papi-dts/papi.d.ts index caaff232a0..d4ab3e9f12 100644 --- a/lib/papi-dts/papi.d.ts +++ b/lib/papi-dts/papi.d.ts @@ -1514,7 +1514,6 @@ declare module 'papi-shared-types' { import { ScriptureReference } from 'papi-components'; import type { DataProviderDataType } from 'shared/models/data-provider.model'; import type { MandatoryProjectDataType } from 'shared/models/project-data-provider.model'; - import { VerseRef } from '@sillsdev/scripture'; /** * Function types for each command available on the papi. Each extension can extend this interface * to add commands that it registers on the papi. @@ -1559,12 +1558,6 @@ declare module 'papi-shared-types' { placeholder: null; } type SettingNames = keyof SettingTypes; - /** This is not yet a complete list of the data types available from Paratext projects. */ - type ParatextStandardProjectDataTypes = MandatoryProjectDataType & { - Book: DataProviderDataType; - Chapter: DataProviderDataType; - Verse: DataProviderDataType; - }; /** This is just a simple example so we have more than one. It's not intended to be real. */ type NotesOnlyProjectDataTypes = MandatoryProjectDataType & { Notes: DataProviderDataType; @@ -1589,7 +1582,6 @@ declare module 'papi-shared-types' { * ``` */ interface ProjectDataTypes { - ParatextStandard: ParatextStandardProjectDataTypes; NotesOnly: NotesOnlyProjectDataTypes; } /** diff --git a/src/declarations/papi-shared-types.ts b/src/declarations/papi-shared-types.ts index e5661636ee..f8b06bcf54 100644 --- a/src/declarations/papi-shared-types.ts +++ b/src/declarations/papi-shared-types.ts @@ -2,7 +2,6 @@ declare module 'papi-shared-types' { import { ScriptureReference } from 'papi-components'; import type { DataProviderDataType } from 'shared/models/data-provider.model'; import type { MandatoryProjectDataType } from '@shared/models/project-data-provider.model'; - import { VerseRef } from '@sillsdev/scripture'; // TODO: Adding an index type removes type checking on the key :( How do we make sure extensions provide only functions? /** @@ -61,13 +60,6 @@ declare module 'papi-shared-types' { export type SettingNames = keyof SettingTypes; - /** This is not yet a complete list of the data types available from Paratext projects. */ - export type ParatextStandardProjectDataTypes = MandatoryProjectDataType & { - Book: DataProviderDataType; - Chapter: DataProviderDataType; - Verse: DataProviderDataType; - }; - /** This is just a simple example so we have more than one. It's not intended to be real. */ export type NotesOnlyProjectDataTypes = MandatoryProjectDataType & { Notes: DataProviderDataType; @@ -93,7 +85,6 @@ declare module 'papi-shared-types' { * ``` */ export interface ProjectDataTypes { - ParatextStandard: ParatextStandardProjectDataTypes; NotesOnly: NotesOnlyProjectDataTypes; } diff --git a/src/main/main.ts b/src/main/main.ts index 22dda886a6..41bf013df1 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -321,12 +321,10 @@ async function main() { // } /* setTimeout(async () => { - const paratextPdp = await getProjectDataProvider( - 'b4c501ad2538989d6fb723518e92408406e232d3', - 'ParatextStandard', - 'paratextFolders', + const paratextPdp = await getProjectDataProvider<'ParatextStandard'>( + '32664dc3288a28df2e2bb75ded887fc8f17a15fb', ); - const verse = await paratextPdp.getVerse(new VerseRef('JHN', '1', '1')); + const verse = await paratextPdp.getVerseUSFM(new VerseRef('JHN', '1', '1')); logger.info(`Got PDP data: ${verse}`); paratextPdp.setExtensionData( { extensionName: 'foo', dataQualifier: 'fooData' }, From 8ad46daf1bc92ac65b9bc47e82ae15f0098e3ecb Mon Sep 17 00:00:00 2001 From: tjcouch-sil Date: Mon, 9 Oct 2023 10:02:02 -0500 Subject: [PATCH 2/2] Referred to PT9 plugin api in ProjectNotes comments --- .../src/project-notes-data-provider/index.d.ts | 16 +++++++++++++++- extensions/src/usfm-data-provider/index.d.ts | 6 +++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/extensions/src/project-notes-data-provider/index.d.ts b/extensions/src/project-notes-data-provider/index.d.ts index c10617b7d8..8003322e46 100644 --- a/extensions/src/project-notes-data-provider/index.d.ts +++ b/extensions/src/project-notes-data-provider/index.d.ts @@ -13,7 +13,15 @@ declare module 'project-notes-data-provider' { Notes: DataProviderDataType; }; - /** Data provider for manipulating project notes */ + /** + * Data provider for manipulating project notes + * + * Modeled from Paratext 9 Plugin API's [GetNotes](https://github.com/ubsicap/paratext_demo_plugins/wiki/IProject#getnotes) + * and [AddNote](https://github.com/ubsicap/paratext_demo_plugins/wiki/IProject#addnote) + * + * WARNING: This is currently designed to match closely with Paratext 9's Notes API. Any changes + * must maintain backwards compatibility for the time being. + */ export type ProjectNotesDataProvider = IDataProvider & { /** * Adds a project note @@ -180,6 +188,12 @@ declare module 'project-notes-data-provider' { /** * Data provider for manipulating project notes * + * Modeled from Paratext 9 Plugin API's [GetNotes](https://github.com/ubsicap/paratext_demo_plugins/wiki/IProject#getnotes) + * and [AddNote](https://github.com/ubsicap/paratext_demo_plugins/wiki/IProject#addnote) + * + * WARNING: This is currently designed to match closely with Paratext 9's Notes API. Any changes + * must maintain backwards compatibility for the time being. + * * This is a hand-written baked-out version of `ProjectNotesDataProvider` for ease of reading */ type ProjectNotesDataProviderExpanded = { diff --git a/extensions/src/usfm-data-provider/index.d.ts b/extensions/src/usfm-data-provider/index.d.ts index a522a3bf19..bcac0d81a0 100644 --- a/extensions/src/usfm-data-provider/index.d.ts +++ b/extensions/src/usfm-data-provider/index.d.ts @@ -23,7 +23,11 @@ declare module 'usfm-data-provider' { } declare module 'papi-shared-types' { - /** This is not yet a complete list of the data types available from Paratext projects. */ + /** + * Provides project data for Paratext Scripture projects. + * + * This is not yet a complete list of the data types available from Paratext projects. + */ export type ParatextStandardProjectDataTypes = MandatoryProjectDataType & { /** Gets the "raw" USFM data for the specified book */ BookUSFM: DataProviderDataType;