Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 66 additions & 1 deletion backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@
}

public async Task<WritingSystem> CreateWritingSystem(WritingSystem writingSystem)
{

Check warning on line 152 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FwHeadless / publish-fw-headless

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 152 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build API / publish-api

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 152 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FW Lite and run tests

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 152 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / GHA integration tests / dotnet

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 152 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Linux

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 152 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 152 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 152 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Windows

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
var type = writingSystem.Type;
var exitingWs = type == WritingSystemType.Analysis ? Cache.ServiceLocator.WritingSystems.AnalysisWritingSystems : Cache.ServiceLocator.WritingSystems.VernacularWritingSystems;
if (exitingWs.Any(ws => ws.Id == writingSystem.WsId))
Expand Down Expand Up @@ -236,7 +236,7 @@
}

public async Task<PartOfSpeech> CreatePartOfSpeech(PartOfSpeech partOfSpeech)
{

Check warning on line 239 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FwHeadless / publish-fw-headless

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 239 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build API / publish-api

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 239 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FW Lite and run tests

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 239 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / GHA integration tests / dotnet

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 239 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Linux

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 239 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 239 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 239 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Windows

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
IPartOfSpeech? lcmPartOfSpeech = null;
if (partOfSpeech.Id == default) partOfSpeech.Id = Guid.NewGuid();
UndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW("Create Part of Speech",
Expand Down Expand Up @@ -438,7 +438,7 @@
}

public async Task<ComplexFormType> CreateComplexFormType(ComplexFormType complexFormType)
{

Check warning on line 441 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FwHeadless / publish-fw-headless

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 441 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build API / publish-api

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 441 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FW Lite and run tests

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 441 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / GHA integration tests / dotnet

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 441 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Linux

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 441 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 441 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 441 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Windows

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
if (complexFormType.Id == default) complexFormType.Id = Guid.NewGuid();
UndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW("Create complex form type",
"Remove complex form type",
Expand Down Expand Up @@ -488,6 +488,70 @@
});
}

public IAsyncEnumerable<MorphTypeData> GetAllMorphTypeData()
{
return
MorphTypeRepository
.AllInstances()
.ToAsyncEnumerable()
.Select(FromLcmMorphType);
}

public Task<MorphTypeData?> GetMorphTypeData(Guid id)
{
MorphTypeRepository.TryGetObject(id, out var lcmMorphType);
if (lcmMorphType is null) return Task.FromResult<MorphTypeData?>(null);
return Task.FromResult<MorphTypeData?>(FromLcmMorphType(lcmMorphType));
}

internal MorphTypeData FromLcmMorphType(IMoMorphType morphType)
{
return new MorphTypeData
{
Id = morphType.Guid,
MorphType = LcmHelpers.FromLcmMorphType(morphType),
Name = FromLcmMultiString(morphType.Name),
Abbreviation = FromLcmMultiString(morphType.Abbreviation),
Description = FromLcmMultiString(morphType.Description),
LeadingToken = morphType.Prefix,
TrailingToken = morphType.Postfix,
SecondaryOrder = morphType.SecondaryOrder,
};
}

public Task<MorphTypeData> CreateMorphTypeData(MorphTypeData morphTypeData)
{
// Creating new morph types not allowed in FwData projects, so silently ignore operation
return Task.FromResult(morphTypeData);
}

public Task<MorphTypeData> UpdateMorphTypeData(Guid id, UpdateObjectInput<MorphTypeData> update)
{
var lcmMorphType = MorphTypeRepository.GetObject(id);
if (lcmMorphType is null) throw new NullReferenceException($"unable to find morph type with id {id}");
UndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW("Update Morph Type",
"Revert Morph Type",
Cache.ServiceLocator.ActionHandler,
() =>
{
var updateProxy = new UpdateMorphTypeDataProxy(lcmMorphType, this);
update.Apply(updateProxy);
});
return Task.FromResult(FromLcmMorphType(lcmMorphType));
}

public async Task<MorphTypeData> UpdateMorphTypeData(MorphTypeData before, MorphTypeData after, IMiniLcmApi? api = null)
{
await MorphTypeDataSync.Sync(before, after, api ?? this);
return await GetMorphTypeData(after.Id) ?? throw new NullReferenceException("unable to find morph type with id " + after.Id);
}

public Task DeleteMorphTypeData(Guid id)
{
// Deleting morph types not allowed in FwData projects, so silently ignore operation
return Task.CompletedTask;
}

public IAsyncEnumerable<VariantType> GetVariantTypes()
{
return VariantTypes.PossibilitiesOS
Expand Down Expand Up @@ -533,6 +597,7 @@
LexemeForm = FromLcmMultiString(entry.LexemeFormOA?.Form),
CitationForm = FromLcmMultiString(entry.CitationForm),
LiteralMeaning = FromLcmMultiString(entry.LiteralMeaning),
MorphType = LcmHelpers.FromLcmMorphType(entry.PrimaryMorphType), // TODO: Decide what to do about entries with *mixed* morph types
Senses = entry.AllSenses.Select(FromLexSense).ToList(),
ComplexFormTypes = ToComplexFormTypes(entry),
Components = ToComplexFormComponents(entry).ToList(),
Expand Down Expand Up @@ -836,7 +901,7 @@
Cache.ServiceLocator.ActionHandler,
() =>
{
var lexEntry = Cache.CreateEntry(entry.Id);
var lexEntry = Cache.CreateEntry(entry.Id, entry.MorphType);
UpdateLcmMultiString(lexEntry.LexemeFormOA.Form, entry.LexemeForm);
UpdateLcmMultiString(lexEntry.CitationForm, entry.CitationForm);
UpdateLcmMultiString(lexEntry.LiteralMeaning, entry.LiteralMeaning);
Expand Down Expand Up @@ -1302,7 +1367,7 @@
throw new InvalidOperationException("Entry not found");
UndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW("Create Sense",
"Remove sense",
Cache.ServiceLocator.ActionHandler,

Check warning on line 1370 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FwHeadless / publish-fw-headless

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 1370 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build API / publish-api

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 1370 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FW Lite and run tests

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 1370 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / GHA integration tests / dotnet

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 1370 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Linux

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 1370 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 1370 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 1370 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Windows

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
() => CreateSense(lexEntry, sense, between));
return FromLexSense(SenseRepository.GetObject(sense.Id));
}
Expand Down Expand Up @@ -1447,7 +1512,7 @@
throw new InvalidOperationException("Sense not found");
UndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW("Create Example Sentence",
"Remove example sentence",
Cache.ServiceLocator.ActionHandler,

Check warning on line 1515 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FwHeadless / publish-fw-headless

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 1515 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build API / publish-api

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 1515 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Build FW Lite and run tests

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 1515 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / GHA integration tests / dotnet

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 1515 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Linux

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 1515 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 1515 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Mac

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 1515 in backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs

View workflow job for this annotation

GitHub Actions / Publish FW Lite app for Windows

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
() => CreateExampleSentence(lexSense, exampleSentence, between));
return FromLexExampleSentence(senseId, ExampleSentenceRepository.GetObject(exampleSentence.Id));
}
Expand Down
102 changes: 96 additions & 6 deletions backend/FwLite/FwDataMiniLcmBridge/Api/LcmHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,66 @@ internal static bool SearchValue(this ITsMultiString multiString, string value)
'\u0640', // Arabic Tatweel
];

internal static MorphType FromLcmMorphType(IMoMorphType? morphType)
{
var lcmMorphTypeId = morphType?.Id.Guid;

return lcmMorphTypeId switch
{
null => MorphType.Unknown,
// Can't switch on Guids since they're not compile-type constants, but thankfully pattern matching works
Guid g when g == MoMorphTypeTags.kguidMorphBoundRoot => MorphType.BoundRoot,
Guid g when g == MoMorphTypeTags.kguidMorphBoundStem => MorphType.BoundStem,
Guid g when g == MoMorphTypeTags.kguidMorphCircumfix => MorphType.Circumfix,
Guid g when g == MoMorphTypeTags.kguidMorphClitic => MorphType.Clitic,
Guid g when g == MoMorphTypeTags.kguidMorphEnclitic => MorphType.Enclitic,
Guid g when g == MoMorphTypeTags.kguidMorphInfix => MorphType.Infix,
Guid g when g == MoMorphTypeTags.kguidMorphParticle => MorphType.Particle,
Guid g when g == MoMorphTypeTags.kguidMorphPrefix => MorphType.Prefix,
Guid g when g == MoMorphTypeTags.kguidMorphProclitic => MorphType.Proclitic,
Guid g when g == MoMorphTypeTags.kguidMorphRoot => MorphType.Root,
Guid g when g == MoMorphTypeTags.kguidMorphSimulfix => MorphType.Simulfix,
Guid g when g == MoMorphTypeTags.kguidMorphStem => MorphType.Stem,
Guid g when g == MoMorphTypeTags.kguidMorphSuffix => MorphType.Suffix,
Guid g when g == MoMorphTypeTags.kguidMorphSuprafix => MorphType.Suprafix,
Guid g when g == MoMorphTypeTags.kguidMorphInfixingInterfix => MorphType.InfixingInterfix,
Guid g when g == MoMorphTypeTags.kguidMorphPrefixingInterfix => MorphType.PrefixingInterfix,
Guid g when g == MoMorphTypeTags.kguidMorphSuffixingInterfix => MorphType.SuffixingInterfix,
Guid g when g == MoMorphTypeTags.kguidMorphPhrase => MorphType.Phrase,
Guid g when g == MoMorphTypeTags.kguidMorphDiscontiguousPhrase => MorphType.DiscontiguousPhrase,
_ => MorphType.Other,
};
}

internal static Guid? ToLcmMorphTypeId(MorphType morphType)
{
return morphType switch
{
MorphType.BoundRoot => MoMorphTypeTags.kguidMorphBoundRoot,
MorphType.BoundStem => MoMorphTypeTags.kguidMorphBoundStem,
MorphType.Circumfix => MoMorphTypeTags.kguidMorphCircumfix,
MorphType.Clitic => MoMorphTypeTags.kguidMorphClitic,
MorphType.Enclitic => MoMorphTypeTags.kguidMorphEnclitic,
MorphType.Infix => MoMorphTypeTags.kguidMorphInfix,
MorphType.Particle => MoMorphTypeTags.kguidMorphParticle,
MorphType.Prefix => MoMorphTypeTags.kguidMorphPrefix,
MorphType.Proclitic => MoMorphTypeTags.kguidMorphProclitic,
MorphType.Root => MoMorphTypeTags.kguidMorphRoot,
MorphType.Simulfix => MoMorphTypeTags.kguidMorphSimulfix,
MorphType.Stem => MoMorphTypeTags.kguidMorphStem,
MorphType.Suffix => MoMorphTypeTags.kguidMorphSuffix,
MorphType.Suprafix => MoMorphTypeTags.kguidMorphSuprafix,
MorphType.InfixingInterfix => MoMorphTypeTags.kguidMorphInfixingInterfix,
MorphType.PrefixingInterfix => MoMorphTypeTags.kguidMorphPrefixingInterfix,
MorphType.SuffixingInterfix => MoMorphTypeTags.kguidMorphSuffixingInterfix,
MorphType.Phrase => MoMorphTypeTags.kguidMorphPhrase,
MorphType.DiscontiguousPhrase => MoMorphTypeTags.kguidMorphDiscontiguousPhrase,
MorphType.Unknown => null,
MorphType.Other => null, // Note that this will not round-trip with FromLcmMorphType
_ => null,
};
}

internal static void ContributeExemplars(ITsMultiString multiString, IReadOnlyDictionary<int, HashSet<char>> wsExemplars)
{
for (var i = 0; i < multiString.StringCount; i++)
Expand Down Expand Up @@ -148,21 +208,51 @@ internal static int GetWritingSystemHandle(this LcmCache cache, WritingSystemId
return multiString.get_String(wsHandle)?.Text ?? null;
}

internal static IMoStemAllomorph CreateLexemeForm(this LcmCache cache)
internal static IMoForm CreateLexemeForm(this LcmCache cache, MorphType morphType)
{
return cache.ServiceLocator.GetInstance<IMoStemAllomorphFactory>().Create();
return
IsAffixMorphType(morphType)
? cache.ServiceLocator.GetInstance<IMoAffixAllomorphFactory>().Create()
: cache.ServiceLocator.GetInstance<IMoStemAllomorphFactory>().Create();
}

internal static ILexEntry CreateEntry(this LcmCache cache, Guid id)
internal static bool IsAffixMorphType(MorphType morphType)
{
return morphType switch
{
// Affixes of all types should use the Affix morph type factory
MorphType.Circumfix => true,
MorphType.Infix => true,
MorphType.Prefix => true,
MorphType.Simulfix => true,
MorphType.Suffix => true,
MorphType.Suprafix => true,
MorphType.InfixingInterfix => true,
MorphType.PrefixingInterfix => true,
MorphType.SuffixingInterfix => true,

// Everything else should use the Stem morph type factory
_ => false,
};
}

internal static ILexEntry CreateEntry(this LcmCache cache, Guid id, MorphType morphType)
{
var lexEntry = cache.ServiceLocator.GetInstance<ILexEntryFactory>().Create(id,
cache.ServiceLocator.GetInstance<ILangProjectRepository>().Singleton.LexDbOA);
lexEntry.LexemeFormOA = cache.CreateLexemeForm();
//must be done after the IMoForm is set on the LexemeForm property
lexEntry.LexemeFormOA.MorphTypeRA = cache.ServiceLocator.GetInstance<IMoMorphTypeRepository>().GetObject(MoMorphTypeTags.kguidMorphStem);
SetLexemeForm(lexEntry, morphType, cache);
return lexEntry;
}

internal static IMoForm SetLexemeForm(ILexEntry lexEntry, MorphType morphType, LcmCache cache)
{
lexEntry.LexemeFormOA = cache.CreateLexemeForm(morphType);
//must be done after the IMoForm is set on the LexemeForm property
var lcmMorphType = ToLcmMorphTypeId(morphType) ?? ToLcmMorphTypeId(MorphType.Stem);
lexEntry.LexemeFormOA.MorphTypeRA = cache.ServiceLocator.GetInstance<IMoMorphTypeRepository>().GetObject(lcmMorphType!.Value);
return lexEntry.LexemeFormOA;
}

internal static string GetSemanticDomainCode(ICmSemanticDomain semanticDomain)
{
var abbr = semanticDomain.Abbreviation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ public override MultiString LexemeForm
{
get
{
_lcmEntry.LexemeFormOA ??= _lexboxLcmApi.Cache.CreateLexemeForm();
return new UpdateMultiStringProxy(_lcmEntry.LexemeFormOA.Form, _lexboxLcmApi);
var form = _lcmEntry.LexemeFormOA ?? LcmHelpers.SetLexemeForm(
_lcmEntry,
LcmHelpers.FromLcmMorphType(_lcmEntry.PrimaryMorphType),
_lexboxLcmApi.Cache);
return new UpdateMultiStringProxy(form.Form, _lexboxLcmApi);
}
set => throw new NotImplementedException();
}
Expand All @@ -39,6 +42,12 @@ public override RichMultiString LiteralMeaning
set => throw new NotImplementedException();
}

public override MorphType MorphType
{
get => throw new NotImplementedException();
set => Console.WriteLine("setting MorphType not implemented"); // Not throwing, for now
}

public override List<Sense> Senses
{
get => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using MiniLcm.Models;
using SIL.LCModel;

namespace FwDataMiniLcmBridge.Api.UpdateProxy;

public class UpdateMorphTypeDataProxy : MorphTypeData
{
private readonly IMoMorphType _lcmMorphType;
private readonly FwDataMiniLcmApi _lexboxLcmApi;

public UpdateMorphTypeDataProxy(IMoMorphType lcmMorphType, FwDataMiniLcmApi lexboxLcmApi)
{
_lcmMorphType = lcmMorphType;
Id = lcmMorphType.Guid;
_lexboxLcmApi = lexboxLcmApi;
}

public override MultiString Name
{
get => new UpdateMultiStringProxy(_lcmMorphType.Name, _lexboxLcmApi);
set => throw new NotImplementedException();
}

public override MultiString Abbreviation
{
get => new UpdateMultiStringProxy(_lcmMorphType.Abbreviation, _lexboxLcmApi);
set => throw new NotImplementedException();
}

public override RichMultiString Description
{
get => new UpdateRichMultiStringProxy(_lcmMorphType.Description, _lexboxLcmApi);
set => throw new NotImplementedException();
}

public override string LeadingToken
{
get => _lcmMorphType.Prefix;
set => _lcmMorphType.Prefix = value;
}

public override string TrailingToken
{
get => _lcmMorphType.Postfix;
set => _lcmMorphType.Postfix = value;
}

public override int SecondaryOrder
{
get => _lcmMorphType.SecondaryOrder;
set => _lcmMorphType.SecondaryOrder = value;
}
}
51 changes: 51 additions & 0 deletions backend/FwLite/FwLiteProjectSync.Tests/IntegerDiffTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using MiniLcm.SyncHelpers;
using SystemTextJsonPatch.Operations;

namespace FwLiteProjectSync.Tests;

public class IntegerDiffTests
{
private record Placeholder();

[Fact]
public void DiffEmptyIntegersDoNothing()
{
int? before = null;
int? after = null;
var result = IntegerDiff.GetIntegerDiff<Placeholder>("test", before, after);
result.Should().BeEmpty();
}

[Fact]
public void DiffOneToEmptyAddsOne()
{
int? before = null;
var after = 1;
var result = IntegerDiff.GetIntegerDiff<Placeholder>("test", before, after);
result.Should().BeEquivalentTo([
new Operation<Placeholder>("add", "/test", null, 1)
]);
}

[Fact]
public void DiffOneToTwoReplacesOne()
{
var before = 1;
var after = 2;
var result = IntegerDiff.GetIntegerDiff<Placeholder>("test", before, after);
result.Should().BeEquivalentTo([
new Operation<Placeholder>("replace", "/test", null, 2)
]);
}

[Fact]
public void DiffNoneToOneRemovesOne()
{
var before = 1;
int? after = null;
var result = IntegerDiff.GetIntegerDiff<Placeholder>("test", before, after);
result.Should().BeEquivalentTo([
new Operation<Placeholder>("remove", "/test", null)
]);
}
}
51 changes: 51 additions & 0 deletions backend/FwLite/FwLiteProjectSync.Tests/SimpleDiffTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using MiniLcm.SyncHelpers;
using SystemTextJsonPatch.Operations;

namespace FwLiteProjectSync.Tests;

public class SimpleStringDiffTests
{
private record Placeholder();

[Fact]
public void DiffEmptyStringsDoNothing()
{
string? before = null;
string? after = null;
var result = SimpleStringDiff.GetStringDiff<Placeholder>("test", before, after);
result.Should().BeEmpty();
}

[Fact]
public void DiffOneToEmptyAddsOne()
{
string? before = null;
var after = "hello";
var result = SimpleStringDiff.GetStringDiff<Placeholder>("test", before, after);
result.Should().BeEquivalentTo([
new Operation<Placeholder>("add", "/test", null, "hello")
]);
}

[Fact]
public void DiffOneToOneReplacesOne()
{
var before = "hello";
var after = "world";
var result = SimpleStringDiff.GetStringDiff<Placeholder>("test", before, after);
result.Should().BeEquivalentTo([
new Operation<Placeholder>("replace", "/test", null, "world")
]);
}

[Fact]
public void DiffNoneToOneRemovesOne()
{
var before = "hello";
string? after = null;
var result = SimpleStringDiff.GetStringDiff<Placeholder>("test", before, after);
result.Should().BeEquivalentTo([
new Operation<Placeholder>("remove", "/test", null)
]);
}
}
Loading
Loading