Skip to content

Commit

Permalink
Reworked ParatextStandard PDP to include USFM in data type names, wro…
Browse files Browse the repository at this point in the history
…te TypeScript types for potential Scripture and Project Note data (#538)
  • Loading branch information
tjcouch-sil authored Oct 9, 2023
2 parents b4e1075 + 8ad46da commit 5f3ce48
Show file tree
Hide file tree
Showing 8 changed files with 599 additions and 45 deletions.
24 changes: 12 additions & 12 deletions c-sharp/Projects/ParatextProjectDataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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);
}
}
20 changes: 10 additions & 10 deletions c-sharp/Projects/ParatextProjectStorageInterpreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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) { }
Expand Down Expand Up @@ -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),
Expand All @@ -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(
Expand All @@ -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}");
}
Expand Down
235 changes: 235 additions & 0 deletions extensions/src/project-notes-data-provider/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
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<ProjectNotesSelector, ProjectNote[], never>;
};

/**
* 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<ProjectNotesProviderDataTypes> & {
/**
* 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<ProjectNote>;
};

/** 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
*
* 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 = {
/** Event emitted when this provider is disposed */
onDidDispose: PapiEvent<void>;
/** Get notes from the provider. `setNotes` is not available; please use `addNote` */
getNotes(notesSelector: ProjectNotesSelector): Promise<ProjectNote[]>;
/**
* 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<ProjectNote>;
};
}
9 changes: 9 additions & 0 deletions extensions/src/project-notes-data-provider/manifest.json
Original file line number Diff line number Diff line change
@@ -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": []
}
Loading

0 comments on commit 5f3ce48

Please sign in to comment.