Refactor language API

This commit is contained in:
IRBorisov 2023-11-06 20:53:14 +03:00
parent 97bec834f0
commit 0e5b013e4e
8 changed files with 129 additions and 127 deletions

View File

@ -2,7 +2,7 @@ import { syntaxTree } from '@codemirror/language'
import { Extension } from '@codemirror/state'; import { Extension } from '@codemirror/state';
import { hoverTooltip } from '@codemirror/view'; import { hoverTooltip } from '@codemirror/view';
import { parseEntityReference, parseSyntacticReference } from '../../models/language'; import { parseEntityReference, parseSyntacticReference } from '../../models/languageAPI';
import { IConstituenta } from '../../models/rsform'; import { IConstituenta } from '../../models/rsform';
import { domTooltipEntityReference, domTooltipSyntacticReference, findContainedNodes, findEnvelopingNodes } from '../../utils/codemirror'; import { domTooltipEntityReference, domTooltipSyntacticReference, findContainedNodes, findEnvelopingNodes } from '../../utils/codemirror';
import { IColorTheme } from '../../utils/color'; import { IColorTheme } from '../../utils/color';

View File

@ -8,11 +8,8 @@ import TextInput from '../../components/Common/TextInput';
import HelpTerminologyControl from '../../components/Help/HelpTerminologyControl'; import HelpTerminologyControl from '../../components/Help/HelpTerminologyControl';
import { HelpIcon } from '../../components/Icons'; import { HelpIcon } from '../../components/Icons';
import ConstituentaPicker from '../../components/Shared/ConstituentaPicker'; import ConstituentaPicker from '../../components/Shared/ConstituentaPicker';
import { import { Grammeme, ReferenceType } from '../../models/language';
getCompatibleGrams, Grammeme, import { getCompatibleGrams, parseEntityReference, parseGrammemes, parseSyntacticReference } from '../../models/languageAPI';
parseEntityReference, parseGrammemes,
parseSyntacticReference, ReferenceType
} from '../../models/language';
import { CstMatchMode } from '../../models/miscelanious'; import { CstMatchMode } from '../../models/miscelanious';
import { IConstituenta } from '../../models/rsform'; import { IConstituenta } from '../../models/rsform';
import { matchConstituenta } from '../../models/rsformAPI'; import { matchConstituenta } from '../../models/rsformAPI';

View File

@ -10,10 +10,8 @@ import HelpTerminologyControl from '../components/Help/HelpTerminologyControl';
import { ArrowLeftIcon, ArrowRightIcon, CheckIcon, ChevronDoubleDownIcon, CrossIcon, HelpIcon } from '../components/Icons'; import { ArrowLeftIcon, ArrowRightIcon, CheckIcon, ChevronDoubleDownIcon, CrossIcon, HelpIcon } from '../components/Icons';
import { useConceptTheme } from '../context/ThemeContext'; import { useConceptTheme } from '../context/ThemeContext';
import useConceptText from '../hooks/useConceptText'; import useConceptText from '../hooks/useConceptText';
import { import { Grammeme, ITextRequest, IWordForm, IWordFormPlain } from '../models/language';
getCompatibleGrams, Grammeme, ITextRequest, IWordForm, import { getCompatibleGrams, matchWordForm, parseGrammemes } from '../models/languageAPI';
IWordFormPlain, matchWordForm, parseGrammemes
} from '../models/language';
import { IConstituenta, TermForm } from '../models/rsform'; import { IConstituenta, TermForm } from '../models/rsform';
import { colorfgGrammeme } from '../utils/color'; import { colorfgGrammeme } from '../utils/color';
import { labelGrammeme } from '../utils/labels'; import { labelGrammeme } from '../utils/labels';

View File

@ -228,94 +228,6 @@ export interface ILexemeData {
items: IWordFormPlain[] items: IWordFormPlain[]
} }
/**
* Equality comparator for {@link IWordForm}. Compares a set of Grammemes attached to wordforms
*/
export function matchWordForm(left: IWordForm, right: IWordForm): boolean {
if (left.grams.length !== right.grams.length) {
return false;
}
for (let index = 0; index < left.grams.length; ++index) {
if (left.grams[index] !== right.grams[index]) {
return false;
}
}
return true;
}
function parseSingleGrammeme(text: string): GramData {
if (Object.values(Grammeme).includes(text as Grammeme)) {
return text as Grammeme;
} else {
return text;
}
}
/**
* Compares {@link GramData} based on Grammeme enum and alpha order for strings.
*/
export function compareGrammemes(left: GramData, right: GramData): number {
const indexLeft = Object.values(Grammeme).findIndex(gram => gram === left as Grammeme);
const indexRight = Object.values(Grammeme).findIndex(gram => gram === right as Grammeme);
if (indexLeft === -1 && indexRight === -1) {
return left.localeCompare(right);
} else if (indexLeft === -1 && indexRight !== -1) {
return 1;
} else if (indexLeft !== -1 && indexRight === -1) {
return -1;
} else {
return indexLeft - indexRight;
}
}
/**
* Transforms {@link Grammeme} enumeration to {@link GramData}.
*/
export function parseGrammemes(termForm: string): GramData[] {
const result: GramData[] = [];
const chunks = termForm.split(',');
chunks.forEach(chunk => {
chunk = chunk.trim();
if (chunk !== '') {
result.push(parseSingleGrammeme(chunk));
}
});
return result.sort(compareGrammemes);
}
/**
* Creates a list of compatible {@link Grammeme}s.
*/
export function getCompatibleGrams(input: Grammeme[]): Grammeme[] {
let result: Grammeme[] = [];
input.forEach(
(gram) => {
if (!result.includes(gram)) {
if (NounGrams.includes(gram)) {
result.push(...NounGrams);
}
if (VerbGrams.includes(gram)) {
result.push(...VerbGrams);
}
}
});
input.forEach(
(gram) => GrammemeGroups.forEach(
(group) => {
if (group.includes(gram)) {
result = result.filter(item => !group.includes(item));
}
}));
if (result.length === 0) {
return [... new Set<Grammeme>([...VerbGrams, ...NounGrams])];
} else {
return result;
}
}
// ====== Reference resolution ===== // ====== Reference resolution =====
/** /**
* Represents text request. * Represents text request.
@ -380,29 +292,3 @@ export interface IResolutionData {
output: string output: string
refs: IResolvedReference[] refs: IResolvedReference[]
} }
/**
* Extracts {@link IEntityReference} from string representation.
*
* @param text - Reference text in a valid pattern. Must fit format '\@\{GLOBAL_ID|GRAMMEMES\}'
*/
export function parseEntityReference(text: string): IEntityReference {
const blocks = text.slice(2, text.length - 1).split('|');
return {
entity: blocks[0].trim(),
form: blocks[1].trim()
}
}
/**
* Extracts {@link ISyntacticReference} from string representation.
*
* @param text - Reference text in a valid pattern. Must fit format '\@\{OFFSET|NOMINAL_FORM\}'
*/
export function parseSyntacticReference(text: string): ISyntacticReference {
const blocks = text.slice(2, text.length - 1).split('|');
return {
offset: Number(blocks[0].trim()),
nominal: blocks[1].trim()
}
}

View File

@ -1,4 +1,5 @@
import { Grammeme, parseEntityReference, parseGrammemes, parseSyntacticReference } from './language'; import { Grammeme } from './language';
import { parseEntityReference, parseGrammemes, parseSyntacticReference } from './languageAPI';
describe('Testing grammeme parsing', () => { describe('Testing grammeme parsing', () => {

View File

@ -0,0 +1,118 @@
/**
* Module: Natural language model API.
*/
import { GramData, Grammeme, GrammemeGroups, IEntityReference, ISyntacticReference, IWordForm, NounGrams, VerbGrams } from './language';
/**
* Equality comparator for {@link IWordForm}. Compares a set of Grammemes attached to wordforms
*/
export function matchWordForm(left: IWordForm, right: IWordForm): boolean {
if (left.grams.length !== right.grams.length) {
return false;
}
for (let index = 0; index < left.grams.length; ++index) {
if (left.grams[index] !== right.grams[index]) {
return false;
}
}
return true;
}
function parseSingleGrammeme(text: string): GramData {
if (Object.values(Grammeme).includes(text as Grammeme)) {
return text as Grammeme;
} else {
return text;
}
}
/**
* Compares {@link GramData} based on Grammeme enum and alpha order for strings.
*/
export function compareGrammemes(left: GramData, right: GramData): number {
const indexLeft = Object.values(Grammeme).findIndex(gram => gram === left as Grammeme);
const indexRight = Object.values(Grammeme).findIndex(gram => gram === right as Grammeme);
if (indexLeft === -1 && indexRight === -1) {
return left.localeCompare(right);
} else if (indexLeft === -1 && indexRight !== -1) {
return 1;
} else if (indexLeft !== -1 && indexRight === -1) {
return -1;
} else {
return indexLeft - indexRight;
}
}
/**
* Transforms {@link Grammeme} enumeration to {@link GramData}.
*/
export function parseGrammemes(termForm: string): GramData[] {
const result: GramData[] = [];
const chunks = termForm.split(',');
chunks.forEach(chunk => {
chunk = chunk.trim();
if (chunk !== '') {
result.push(parseSingleGrammeme(chunk));
}
});
return result.sort(compareGrammemes);
}
/**
* Creates a list of compatible {@link Grammeme}s.
*/
export function getCompatibleGrams(input: Grammeme[]): Grammeme[] {
let result: Grammeme[] = [];
input.forEach(
(gram) => {
if (!result.includes(gram)) {
if (NounGrams.includes(gram)) {
result.push(...NounGrams);
}
if (VerbGrams.includes(gram)) {
result.push(...VerbGrams);
}
}
});
input.forEach(
(gram) => GrammemeGroups.forEach(
(group) => {
if (group.includes(gram)) {
result = result.filter(item => !group.includes(item));
}
}));
if (result.length === 0) {
return [... new Set<Grammeme>([...VerbGrams, ...NounGrams])];
} else {
return result;
}
}
/**
* Extracts {@link IEntityReference} from string representation.
*
* @param text - Reference text in a valid pattern. Must fit format '\@\{GLOBAL_ID|GRAMMEMES\}'
*/
export function parseEntityReference(text: string): IEntityReference {
const blocks = text.slice(2, text.length - 1).split('|');
return {
entity: blocks[0].trim(),
form: blocks[1].trim()
}
}
/**
* Extracts {@link ISyntacticReference} from string representation.
*
* @param text - Reference text in a valid pattern. Must fit format '\@\{OFFSET|NOMINAL_FORM\}'
*/
export function parseSyntacticReference(text: string): ISyntacticReference {
const blocks = text.slice(2, text.length - 1).split('|');
return {
offset: Number(blocks[0].trim()),
nominal: blocks[1].trim()
}
}

View File

@ -2,7 +2,8 @@ import { syntaxTree } from '@codemirror/language'
import { NodeType, Tree, TreeCursor } from '@lezer/common' import { NodeType, Tree, TreeCursor } from '@lezer/common'
import { ReactCodeMirrorRef, SelectionRange } from '@uiw/react-codemirror' import { ReactCodeMirrorRef, SelectionRange } from '@uiw/react-codemirror'
import { IEntityReference, ISyntacticReference, parseGrammemes } from '../models/language' import { IEntityReference, ISyntacticReference } from '../models/language'
import { parseGrammemes } from '../models/languageAPI'
import { IConstituenta } from '../models/rsform' import { IConstituenta } from '../models/rsform'
import { colorfgGrammeme,IColorTheme } from './color' import { colorfgGrammeme,IColorTheme } from './color'
import { describeConstituentaTerm, labelCstTypification, labelGrammeme } from './labels' import { describeConstituentaTerm, labelCstTypification, labelGrammeme } from './labels'

View File

@ -1,7 +1,8 @@
// Module: Selector maps // Module: Selector maps
import { LayoutTypes } from 'reagraph'; import { LayoutTypes } from 'reagraph';
import { compareGrammemes,type GramData, Grammeme, ReferenceType } from '../models/language'; import { type GramData, Grammeme, ReferenceType } from '../models/language';
import { compareGrammemes } from '../models/languageAPI';
import { CstType } from '../models/rsform'; import { CstType } from '../models/rsform';
import { ColoringScheme } from '../pages/RSFormPage/EditorTermGraph'; import { ColoringScheme } from '../pages/RSFormPage/EditorTermGraph';
import { labelGrammeme, labelReferenceType } from './labels'; import { labelGrammeme, labelReferenceType } from './labels';