diff --git a/rsconcept/frontend/src/context/LibraryContext.tsx b/rsconcept/frontend/src/context/LibraryContext.tsx index 522744ad..8a2b719b 100644 --- a/rsconcept/frontend/src/context/LibraryContext.tsx +++ b/rsconcept/frontend/src/context/LibraryContext.tsx @@ -1,8 +1,8 @@ import { createContext, useCallback, useContext, useEffect, useState } from 'react'; import { ErrorInfo } from '../components/BackendError'; -import { matchLibraryItem } from '../models/library'; import { ILibraryItem } from '../models/library'; +import { matchLibraryItem } from '../models/libraryAPI'; import { ILibraryFilter } from '../models/miscelanious'; import { IRSForm, IRSFormCreateData, IRSFormData } from '../models/rsform'; import { loadRSFormData } from '../models/rsformAPI'; @@ -68,7 +68,7 @@ export const LibraryState = ({ children }: LibraryStateProps) => { result = result.filter(item => user?.subscriptions.includes(item.id) || item.owner === user?.id); } if (params.query) { - result = result.filter(item => matchLibraryItem(params.query!, item)); + result = result.filter(item => matchLibraryItem(item, params.query!)); } return result; }, [items, user]); diff --git a/rsconcept/frontend/src/main.tsx b/rsconcept/frontend/src/main.tsx index 11e57ed0..6f548cfe 100644 --- a/rsconcept/frontend/src/main.tsx +++ b/rsconcept/frontend/src/main.tsx @@ -44,5 +44,5 @@ createRoot(document.getElementById('root')!).render( - , + ) diff --git a/rsconcept/frontend/src/models/language.ts b/rsconcept/frontend/src/models/language.ts index 61890b60..ba4f0dae 100644 --- a/rsconcept/frontend/src/models/language.ts +++ b/rsconcept/frontend/src/models/language.ts @@ -260,6 +260,7 @@ export interface ISyntacticReference { nominal: string } + /** * Represents text 0-indexed position inside another text. */ diff --git a/rsconcept/frontend/src/models/library.ts b/rsconcept/frontend/src/models/library.ts index 3cd6684e..caa08629 100644 --- a/rsconcept/frontend/src/models/library.ts +++ b/rsconcept/frontend/src/models/library.ts @@ -1,8 +1,11 @@ -// Module: Schema library models. +/** + * Module: Models for Library entities and Users. + */ -import { TextMatcher } from '../utils/utils' - -// ========= Users =========== +/** + * Represents user detailed information. + * Some information should only be accesible to authorized users +*/ export interface IUser { id: number | null username: string @@ -11,31 +14,63 @@ export interface IUser { first_name: string last_name: string } + +/** + * Represents CurrentUser information. +*/ export interface ICurrentUser extends Pick { subscriptions: number[] } + +/** + * Represents login data, used to authentificate users. +*/ export interface IUserLoginData extends Pick { password: string } + +/** + * Represents signup data, used to create new users. +*/ export interface IUserSignupData extends Omit { password: string password2: string } + +/** + * Represents user data, intended to update user profile in persistent storage. +*/ export interface IUserUpdateData extends Omit { } +/** + * Represents user profile for viewing and editing {@link IUser}. +*/ export interface IUserProfile extends Omit { } + +/** + * Represents user reference information. +*/ export interface IUserInfo extends Omit { } + +/** + * Represents data needed to update password for current user. +*/ export interface IUserUpdatePassword { old_password: string new_password: string } -// ========== LibraryItem ============ +/** + * Represents type of library items. +*/ export enum LibraryItemType { RSFORM = 'rsform', OPERATIONS_SCHEMA = 'oss' } +/** + * Represents library item common data typical for all item types. +*/ export interface ILibraryItem { id: number item_type: LibraryItemType @@ -49,13 +84,9 @@ export interface ILibraryItem { owner: number | null } +/** + * Represents update data for editing {@link ILibraryItem}. +*/ export interface ILibraryUpdateData extends Omit { -} - -// ============= API =============== -export function matchLibraryItem(query: string, target: ILibraryItem): boolean { - const matcher = new TextMatcher(query); - return matcher.test(target.alias) || matcher.test(target.title); -} - +} \ No newline at end of file diff --git a/rsconcept/frontend/src/models/libraryAPI.ts b/rsconcept/frontend/src/models/libraryAPI.ts new file mode 100644 index 00000000..cc25ce21 --- /dev/null +++ b/rsconcept/frontend/src/models/libraryAPI.ts @@ -0,0 +1,18 @@ +/** + * Module: API for Library entities and Users. + */ + +import { TextMatcher } from '../utils/utils'; +import { ILibraryItem } from './library'; + +/** + * Checks if a given target {@link ILibraryItem} matches the specified query. + * + * @param target - item to be matched + * @param query - text to be found in target attributes + */ +export function matchLibraryItem(target: ILibraryItem, query: string): boolean { + const matcher = new TextMatcher(query); + return matcher.test(target.alias) || matcher.test(target.title); +} + diff --git a/rsconcept/frontend/src/models/miscelanious.ts b/rsconcept/frontend/src/models/miscelanious.ts index a2d668d6..0fd08b09 100644 --- a/rsconcept/frontend/src/models/miscelanious.ts +++ b/rsconcept/frontend/src/models/miscelanious.ts @@ -1,6 +1,6 @@ -// Module: Miscellanious frontend model types. - -import { IConstituenta, IRSForm } from './rsform' +/** + * Module: Miscellanious frontend model types. Future tagets for refactoring aimed at extracting modules. + */ /** * Represents graph dependency mode. @@ -84,23 +84,3 @@ export interface GraphEditorParams { allowConstant: boolean allowTheorem: boolean } - -// ================== API ==================== -export function applyGraphFilter(schema: IRSForm, start: number, mode: DependencyMode): IConstituenta[] { - if (mode === DependencyMode.ALL) { - return schema.items - } - let ids: number[] | undefined = undefined - switch (mode) { - case DependencyMode.OUTPUTS: { ids = schema.graph.nodes.get(start)?.outputs; break} - case DependencyMode.INPUTS: { ids = schema.graph.nodes.get(start)?.inputs; break} - case DependencyMode.EXPAND_OUTPUTS: { ids = schema.graph.expandOutputs([start]); break} - case DependencyMode.EXPAND_INPUTS: { ids = schema.graph.expandInputs([start]); break} - } - if (!ids) { - return schema.items - } else { - return schema.items.filter(cst => ids!.find(id => id === cst.id)) - } -} - diff --git a/rsconcept/frontend/src/models/miscelaniousAPI.ts b/rsconcept/frontend/src/models/miscelaniousAPI.ts new file mode 100644 index 00000000..40e35ab4 --- /dev/null +++ b/rsconcept/frontend/src/models/miscelaniousAPI.ts @@ -0,0 +1,29 @@ +/** + * Module: API for miscellanious frontend model types. Future tagets for refactoring aimed at extracting modules. + */ + +import { DependencyMode } from './miscelanious'; +import { IConstituenta, IRSForm } from './rsform'; + + +/** + * Filter list of {@link ILibraryItem} to a given query. + */ +export function applyGraphFilter(target: IRSForm, start: number, mode: DependencyMode): IConstituenta[] { + if (mode === DependencyMode.ALL) { + return target.items + } + let ids: number[] | undefined = undefined + switch (mode) { + case DependencyMode.OUTPUTS: { ids = target.graph.nodes.get(start)?.outputs; break} + case DependencyMode.INPUTS: { ids = target.graph.nodes.get(start)?.inputs; break} + case DependencyMode.EXPAND_OUTPUTS: { ids = target.graph.expandOutputs([start]); break} + case DependencyMode.EXPAND_INPUTS: { ids = target.graph.expandInputs([start]); break} + } + if (!ids) { + return target.items + } else { + return target.items.filter(cst => ids!.find(id => id === cst.id)) + } +} + diff --git a/rsconcept/frontend/src/models/rsform.ts b/rsconcept/frontend/src/models/rsform.ts index 955bb627..ca3fb1f4 100644 --- a/rsconcept/frontend/src/models/rsform.ts +++ b/rsconcept/frontend/src/models/rsform.ts @@ -1,8 +1,15 @@ +/** + * Module: Models for formal representation for systems of concepts. + */ + import { Graph } from '../utils/Graph' import { ILibraryUpdateData } from './library' import { ILibraryItem } from './library' import { IArgumentInfo, ParsingStatus, ValueClass } from './rslang' +/** + * Represents Constituenta type. +*/ export enum CstType { BASE = 'basic', STRUCTURED = 'structure', @@ -17,6 +24,9 @@ export enum CstType { // CstType constant for category dividers in TemplateSchemas. TODO: create separate sctructure for templates export const CATEGORY_CST_TYPE = CstType.THEOREM; +/** + * Represents Constituenta classification in terms of system of concepts. +*/ export enum CstClass { BASIC = 'basic', DERIVED = 'derived', @@ -24,7 +34,9 @@ export enum CstClass { TEMPLATE = 'template' } -// Constituenta expression status +/** + * Represents formal expression Status. +*/ export enum ExpressionStatus { VERIFIED = 'verified', INCORRECT = 'incorrect', @@ -34,12 +46,17 @@ export enum ExpressionStatus { UNKNOWN = 'unknown', } +/** + * Represents word form for natural languange. +*/ export interface TermForm { text: string tags: string } -// ====== Constituenta ========== +/** + * Represents Constituenta basic persistent data. +*/ export interface IConstituentaMeta { id: number schema: number @@ -55,6 +72,9 @@ export interface IConstituentaMeta { term_forms: TermForm[] } +/** + * Represents Constituenta. +*/ export interface IConstituenta extends IConstituentaMeta { cst_class: CstClass @@ -69,10 +89,16 @@ extends IConstituentaMeta { } } +/** + * Represents Constituenta list. +*/ export interface IConstituentaList { items: number[] } +/** + * Represents constituenta data, used in creation process. +*/ export interface ICstCreateData extends Pick< IConstituentaMeta, @@ -82,23 +108,37 @@ extends Pick< insert_after: number | null } +/** + * Represents data, used in ordering constituents in a list. +*/ export interface ICstMovetoData extends IConstituentaList { move_to: number } +/** + * Represents data, used in updating persistent attributes in {@link IConstituenta}. +*/ export interface ICstUpdateData extends Pick, Partial> {} +/** + * Represents data, used in renaming {@link IConstituenta}. +*/ export interface ICstRenameData extends Pick {} +/** + * Represents data response when creating {@link IConstituenta}. +*/ export interface ICstCreatedResponse { new_cst: IConstituentaMeta schema: IRSFormData } -// ========== RSForm ============ +/** + * Represents {@link IRSForm} statistics. +*/ export interface IRSFormStats { count_all: number count_errors: number @@ -119,6 +159,9 @@ export interface IRSFormStats { count_theorem: number } +/** + * Represents formal explication for set of concepts. +*/ export interface IRSForm extends ILibraryItem { items: IConstituenta[] @@ -127,14 +170,23 @@ extends ILibraryItem { subscribers: number[] } +/** + * Represents data for {@link IRSForm} provided by backend. +*/ export interface IRSFormData extends Omit {} +/** + * Represents data, used for creating {@link IRSForm}. +*/ export interface IRSFormCreateData extends ILibraryUpdateData { file?: File fileName?: string } +/** + * Represents data, used for uploading {@link IRSForm} as file. +*/ export interface IRSFormUploadData { load_metadata: boolean file: File diff --git a/rsconcept/frontend/src/models/rsformAPI.ts b/rsconcept/frontend/src/models/rsformAPI.ts index c412cd64..eab19bd0 100644 --- a/rsconcept/frontend/src/models/rsformAPI.ts +++ b/rsconcept/frontend/src/models/rsformAPI.ts @@ -1,4 +1,7 @@ -// ========== RSForm API ================= +/** + * Module: API for formal representation for systems of concepts. + */ + import { Graph } from '../utils/Graph'; import { TextMatcher } from '../utils/utils'; import { CstMatchMode } from './miscelanious'; @@ -9,8 +12,15 @@ import { import { ParsingStatus, ValueClass } from './rslang'; import { extractGlobals } from './rslangAPI'; -export function loadRSFormData(schema: IRSFormData): IRSForm { - const result = schema as IRSForm +/** + * Loads data into an {@link IRSForm} based on {@link IRSFormData}. + * + * @remarks + * This function processes the provided input, initializes the IRSForm, and calculates statistics + * based on the loaded data. It also establishes dependencies between concepts in the graph. + */ +export function loadRSFormData(input: IRSFormData): IRSForm { + const result = input as IRSForm result.graph = new Graph; if (!result.items) { result.stats = { @@ -75,7 +85,7 @@ export function loadRSFormData(schema: IRSFormData): IRSForm { result.graph.addNode(cst.id); const dependencies = extractGlobals(cst.definition_formal); dependencies.forEach(value => { - const source = schema.items.find(cst => cst.alias === value) + const source = input.items.find(cst => cst.alias === value) if (source) { result.graph.addEdge(source.id, cst.id); } @@ -84,6 +94,13 @@ export function loadRSFormData(schema: IRSFormData): IRSForm { return result; } +/** + * Checks if a given target {@link IConstituenta} matches the specified query using the provided matching mode. + * + * @param target - The target object to be matched. + * @param query - The query string used for matching. + * @param mode - The matching mode to determine which properties to include in the matching process. + */ export function matchConstituenta(target: IConstituenta, query: string, mode: CstMatchMode): boolean { const matcher = new TextMatcher(query); if ((mode === CstMatchMode.ALL || mode === CstMatchMode.NAME) && @@ -104,6 +121,20 @@ export function matchConstituenta(target: IConstituenta, query: string, mode: Cs return false; } +/** + * Infers the status of an expression based on parsing and value information. + * + * @param parse - parsing status of the expression. + * @param value - value class of the expression. + * + * @returns The inferred expression status: + * - `ExpressionStatus.UNDEFINED` if either parsing or value is not provided. + * - `ExpressionStatus.UNKNOWN` if parsing status is `ParsingStatus.UNDEF`. + * - `ExpressionStatus.INCORRECT` if parsing status is `ParsingStatus.INCORRECT`. + * - `ExpressionStatus.INCALCULABLE` if value is `ValueClass.INVALID`. + * - `ExpressionStatus.PROPERTY` if value is `ValueClass.PROPERTY`. + * - `ExpressionStatus.VERIFIED` if both parsing and value are valid. + */ export function inferStatus(parse?: ParsingStatus, value?: ValueClass): ExpressionStatus { if (!parse || !value) { return ExpressionStatus.UNDEFINED; @@ -123,11 +154,26 @@ export function inferStatus(parse?: ParsingStatus, value?: ValueClass): Expressi return ExpressionStatus.VERIFIED; } +/** + * Checks if given expression is a template. + */ export function inferTemplate(expression: string): boolean { const match = expression.match(/R\d+/g); return (match && match?.length > 0) ?? false; } +/** + * Infers the {@link CstClass} based on the provided {@link CstType} and template status. + * + * @param type - The CstType representing the type of the Constituenta. + * @param isTemplate - A boolean indicating whether the Constituenta is a template. + * + * @returns The inferred CstClass based on the combination of CstType and template status: + * - `CstClass.TEMPLATE` if the Constituenta is a template. + * - `CstClass.BASIC` if the CstType is BASE, CONSTANT, or STRUCTURED. + * - `CstClass.DERIVED` if the CstType is TERM, FUNCTION, or PREDICATE. + * - `CstClass.STATEMENT` if the CstType is AXIOM or THEOREM. + */ export function inferClass(type: CstType, isTemplate: boolean): CstClass { if (isTemplate) { return CstClass.TEMPLATE; @@ -144,11 +190,16 @@ export function inferClass(type: CstType, isTemplate: boolean): CstClass { } } -export function isMockCst(cst: IConstituenta) { - return cst.id <= 0; -} - -export function createMockConstituenta(schema: number, id: number, alias: string, type: CstType, comment: string): IConstituenta { +/** + * Creates a mock {@link IConstituenta} object with the provided parameters and default values for other properties. + */ +export function createMockConstituenta( + schema: number, + id: number, + alias: string, + type: CstType, + comment: string +): IConstituenta { return { id: id, order: -1, @@ -175,16 +226,26 @@ export function createMockConstituenta(schema: number, id: number, alias: string }; } -export function applyFilterCategory(target: IConstituenta, schema: IRSFormData): IConstituenta[] { +/** + * Checks if given {@link IConstituenta} is mock. + */ +export function isMockCst(cst: IConstituenta) { + return cst.id <= 0; +} + +/** + * TODO: description + */ +export function applyFilterCategory(start: IConstituenta, schema: IRSFormData): IConstituenta[] { const nextCategory = schema.items.find( cst => ( - cst.order > target.order && + cst.order > start.order && cst.cst_type === CATEGORY_CST_TYPE ) ); return schema.items.filter( cst => ( - cst.order > target.order && + cst.order > start.order && (!nextCategory || cst.order <= nextCategory.order) ) ); diff --git a/rsconcept/frontend/src/models/rslang.ts b/rsconcept/frontend/src/models/rslang.ts index 537248bf..631ca781 100644 --- a/rsconcept/frontend/src/models/rslang.ts +++ b/rsconcept/frontend/src/models/rslang.ts @@ -1,28 +1,44 @@ -// Module: RSLang model types +/** + * Module: Models for RSLanguage. + */ -// ======== RS Parsing ============ +/** + * Represents formal expression. +*/ export interface IRSExpression { expression: string } +/** + * Represents syntax type. +*/ export enum Syntax { UNDEF = 'undefined', ASCII = 'ascii', MATH = 'math' } +/** + * Represents computability class. +*/ export enum ValueClass { - INVALID = 'invalid', + INVALID = 'invalid', // incalculable VALUE = 'value', PROPERTY = 'property' } +/** + * Represents parsing status. +*/ export enum ParsingStatus { UNDEF = 'undefined', VERIFIED = 'verified', INCORRECT = 'incorrect' } +/** + * Represents parsing error description. +*/ export interface IRSErrorDescription { errorType: RSErrorType position: number @@ -30,6 +46,9 @@ export interface IRSErrorDescription { params: string[] } +/** + * Represents AST node. +*/ export interface ISyntaxTreeNode { uid: number parent: number @@ -41,17 +60,30 @@ export interface ISyntaxTreeNode { value: unknown } } + +/** + * Represents Syntax tree for RSLang expression. +*/ export type SyntaxTree = ISyntaxTreeNode[] +/** + * Represents function argument definition. +*/ export interface IArgumentInfo { alias: string typification: string } +/** + * Represents function argument value. +*/ export interface IArgumentValue extends IArgumentInfo { value?: string } +/** + * Represents results of expression parse in RSLang. +*/ export interface IExpressionParse { parseResult: boolean syntax: Syntax @@ -63,7 +95,9 @@ export interface IExpressionParse { args: IArgumentInfo[] } -//! RS language token types enumeration +/** + * Represents RSLang token types. +*/ export enum TokenID { // Global, local IDs and literals ID_LOCAL = 258, @@ -225,26 +259,12 @@ export enum RSErrorType { globalFuncNoInterpretation = 34883 } -// Error handling +/** + * Represents error class. +*/ export enum RSErrorClass { LEXER, PARSER, SEMANTIC, UNKNOWN -} - -const ERRCODE_LEXER_MASK = 512; -const ERRCODE_PARSER_MASK = 1024; -const ERRCODE_TYPE_MASK = 2048; - -export function resolveErrorClass(error: RSErrorType): RSErrorClass { - if ((error & ERRCODE_LEXER_MASK) !== 0) { - return RSErrorClass.LEXER; - } else if ((error & ERRCODE_PARSER_MASK) !== 0) { - return RSErrorClass.PARSER; - } else if ((error & ERRCODE_TYPE_MASK) !== 0) { - return RSErrorClass.SEMANTIC; - } else { - return RSErrorClass.UNKNOWN; - } } \ No newline at end of file diff --git a/rsconcept/frontend/src/models/rslangAPI.ts b/rsconcept/frontend/src/models/rslangAPI.ts index fe4fa0c9..05b0bc80 100644 --- a/rsconcept/frontend/src/models/rslangAPI.ts +++ b/rsconcept/frontend/src/models/rslangAPI.ts @@ -1,15 +1,23 @@ -// Module: RSLang model API +/** + * Module: API for RSLanguage. + */ import { applyPattern } from '../utils/utils'; import { CstType } from './rsform'; -import { IArgumentValue } from './rslang' +import { IArgumentValue, RSErrorClass, RSErrorType } from './rslang' const LOCALS_REGEXP = /[_a-zα-ω][a-zα-ω]*\d*/g; +/** + * Extracts global variable names from a given expression. + */ export function extractGlobals(expression: string): Set { return new Set(expression.match(/[XCSADFPT]\d+/g) ?? []); } +/** + * Infers type of constituent for a given template and arguments. + */ export function inferTemplatedType(templateType: CstType, args: IArgumentValue[]): CstType { if (args.length === 0 || args.some(arg => !arg.value)) { return templateType; @@ -20,6 +28,20 @@ export function inferTemplatedType(templateType: CstType, args: IArgumentValue[] } } +/** + * Splits a string containing a template definition into its head and body parts. + * + * A template definition is expected to have the following format: `[head] body`. + * If the input string does not contain the opening square bracket '[', the entire + * string is treated as the body, and an empty string is assigned to the head. + * If the opening bracket is present, the function attempts to find the matching + * closing bracket ']' to determine the head and body parts. + * + * @example + * const template = "[header] body content"; + * const result = splitTemplateDefinition(template); + * // result: `{ head: 'header', body: 'body content' }` + */ export function splitTemplateDefinition(target: string) { let start = 0; for (; start < target.length && target[start] !== '['; ++start) ; @@ -45,6 +67,13 @@ export function splitTemplateDefinition(target: string) { } } +/** + * Substitutes values for template arguments in a given expression. + * + * This function takes an input mathematical expression and a list of argument values. + * It replaces template argument placeholders in the expression with their corresponding values + * from the provided arguments. + */ export function substituteTemplateArgs(expression: string, args: IArgumentValue[]): string { if (args.every(arg => !arg.value)) { return expression; @@ -73,3 +102,22 @@ export function substituteTemplateArgs(expression: string, args: IArgumentValue[ return `[${head}] ${body}` } } + +const ERRCODE_LEXER_MASK = 512; +const ERRCODE_PARSER_MASK = 1024; +const ERRCODE_TYPE_MASK = 2048; + +/** + * Infers error class from error type (code). + */ +export function inferErrorClass(error: RSErrorType): RSErrorClass { + if ((error & ERRCODE_LEXER_MASK) !== 0) { + return RSErrorClass.LEXER; + } else if ((error & ERRCODE_PARSER_MASK) !== 0) { + return RSErrorClass.PARSER; + } else if ((error & ERRCODE_TYPE_MASK) !== 0) { + return RSErrorClass.SEMANTIC; + } else { + return RSErrorClass.UNKNOWN; + } +} \ No newline at end of file diff --git a/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx b/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx index aa599815..a4398495 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx @@ -13,7 +13,7 @@ import useLocalStorage from '../../../hooks/useLocalStorage'; import useWindowSize from '../../../hooks/useWindowSize'; import { DependencyMode as CstSource } from '../../../models/miscelanious'; import { CstMatchMode } from '../../../models/miscelanious'; -import { applyGraphFilter } from '../../../models/miscelanious'; +import { applyGraphFilter } from '../../../models/miscelaniousAPI'; import { CstType, IConstituenta } from '../../../models/rsform'; import { createMockConstituenta, isMockCst, matchConstituenta } from '../../../models/rsformAPI'; import { extractGlobals } from '../../../models/rslangAPI'; diff --git a/rsconcept/frontend/src/utils/Graph.ts b/rsconcept/frontend/src/utils/Graph.ts index b0ec1dfa..011127ea 100644 --- a/rsconcept/frontend/src/utils/Graph.ts +++ b/rsconcept/frontend/src/utils/Graph.ts @@ -1,3 +1,7 @@ +/** + * Module: Custom graph data structure. + */ + /** * Represents single node of a {@link Graph}, as implemented by storing outgoing and incoming connections. */ diff --git a/rsconcept/frontend/src/utils/backendAPI.ts b/rsconcept/frontend/src/utils/backendAPI.ts index d1f5a0aa..96acbdba 100644 --- a/rsconcept/frontend/src/utils/backendAPI.ts +++ b/rsconcept/frontend/src/utils/backendAPI.ts @@ -1,3 +1,7 @@ +/** + * Module: API for backend communications. + */ + import axios, { AxiosError, AxiosRequestConfig } from 'axios'; import { toast } from 'react-toastify'; @@ -17,12 +21,12 @@ import { ICstCreateData, ICstCreatedResponse, ICstMovetoData, ICstRenameData, ICstUpdateData, IRSFormCreateData, IRSFormData, IRSFormUploadData} from '../models/rsform'; import { IExpressionParse, IRSExpression } from '../models/rslang'; -import { config } from './constants'; +import { buidConstants } from './constants'; const defaultOptions = { xsrfCookieName: 'csrftoken', xsrfHeaderName: 'x-csrftoken', - baseURL: `${config.backend}`, + baseURL: `${buidConstants.backend}`, withCredentials: true } diff --git a/rsconcept/frontend/src/utils/codemirror.ts b/rsconcept/frontend/src/utils/codemirror.ts index 0d028d24..e23daeee 100644 --- a/rsconcept/frontend/src/utils/codemirror.ts +++ b/rsconcept/frontend/src/utils/codemirror.ts @@ -1,3 +1,7 @@ +/** + * Module: CodeMirror customizations. + */ + import { syntaxTree } from '@codemirror/language' import { NodeType, Tree, TreeCursor } from '@lezer/common' import { ReactCodeMirrorRef, SelectionRange } from '@uiw/react-codemirror' diff --git a/rsconcept/frontend/src/utils/color.ts b/rsconcept/frontend/src/utils/color.ts index cf046bd1..230a1ea5 100644 --- a/rsconcept/frontend/src/utils/color.ts +++ b/rsconcept/frontend/src/utils/color.ts @@ -1,11 +1,15 @@ -// =========== Modules contains all dynamic color definitions ========== +/** + * Module: Single place for all color definitions in code (see index.css for full defs). + */ import { GramData, Grammeme, NounGrams, PartOfSpeech, VerbGrams } from '../models/language' import { CstClass, ExpressionStatus } from '../models/rsform' import { ISyntaxTreeNode, TokenID } from '../models/rslang' -// ============= MAIN COLOR THEMES ========== +/** + * Represents application color theme configuration. + */ export interface IColorTheme { bgDefault: string bgInput: string @@ -39,7 +43,9 @@ export interface IColorTheme { fgOrange: string } -// ======= Light ======= +/** + * Represents application Light theme. + */ export const lightT: IColorTheme = { bgDefault: 'var(--cl-bg-100)', bgInput: 'var(--cl-bg-120)', @@ -73,7 +79,9 @@ export const lightT: IColorTheme = { fgOrange: 'hsl(030, 090%, 055%)' }; -// ======= DARK ======== +/** + * Represents application Dark theme. + */ export const darkT: IColorTheme = { bgDefault: 'var(--cd-bg-100)', bgInput: 'var(--cd-bg-120)', @@ -107,7 +115,9 @@ export const darkT: IColorTheme = { fgOrange: 'hsl(035, 100%, 050%)' }; -// ============ SELECT THEMES ========== +/** + * Represents Select component Light theme. + */ export const selectLightT = { primary: lightT.bgPrimary, primary75: lightT.bgSelected, @@ -130,6 +140,9 @@ export const selectLightT = { neutral90: lightT.fgWarning } +/** + * Represents Select component Dark theme. + */ export const selectDarkT = { primary: darkT.bgPrimary, primary75: darkT.bgSelected, @@ -152,7 +165,9 @@ export const selectDarkT = { neutral90: darkT.fgWarning } -// ============ GRAPH THEMES ========== +/** + * Represents Graph component Light theme. + */ export const graphLightT = { canvas: { background: '#f9fafb', @@ -202,6 +217,9 @@ export const graphLightT = { } } +/** + * Represents Graph component Dark theme. + */ export const graphDarkT = { canvas: { background: '#171717' // var(--cd-bg-100) @@ -251,7 +269,9 @@ export const graphDarkT = { } } -// ======== Bracket Matching Themes =========== +/** + * Represents Brackets highlights Light theme. + */ export const bracketsLightT = { '.cc-nonmatchingBracket': { color: lightT.fgRed, @@ -263,6 +283,9 @@ export const bracketsLightT = { }, }; +/** + * Represents Brackets highlights Dark theme. + */ export const bracketsDarkT = { '.cc-nonmatchingBracket': { color: darkT.fgRed, @@ -274,7 +297,9 @@ export const bracketsDarkT = { }, }; -// =========== Misc colors ====================== +/** + * Determines background color for {@link ISyntaxTreeNode} based on its type. + */ export function colorbgSyntaxTree(node: ISyntaxTreeNode, colors: IColorTheme): string { switch (node.typeID) { case TokenID.PUNC_DEFINE: @@ -354,6 +379,9 @@ export function colorbgSyntaxTree(node: ISyntaxTreeNode, colors: IColorTheme): s return colors.bgRed; } +/** + * Determines background color for {@link ExpressionStatus}. + */ export function colorbgCstStatus(status: ExpressionStatus, colors: IColorTheme): string { switch (status) { case ExpressionStatus.VERIFIED: return colors.bgGreen; @@ -365,6 +393,9 @@ export function colorbgCstStatus(status: ExpressionStatus, colors: IColorTheme): } } +/** + * Determines foreground color for {@link ExpressionStatus}. + */ export function colorfgCstStatus(status: ExpressionStatus, colors: IColorTheme): string { switch (status) { case ExpressionStatus.VERIFIED: return colors.fgGreen; @@ -376,6 +407,9 @@ export function colorfgCstStatus(status: ExpressionStatus, colors: IColorTheme): } } +/** + * Determines background color for {@link IConstituenta} depending on its {@link CstClass}. + */ export function colorbgCstClass(cstClass: CstClass, colors: IColorTheme): string { switch (cstClass) { case CstClass.BASIC: return colors.bgGreen; @@ -385,6 +419,25 @@ export function colorbgCstClass(cstClass: CstClass, colors: IColorTheme): string } } +/** + * Determines background color for {@link GramData}. + */ +export function colorbgGrammeme(gram: GramData, colors: IColorTheme): string { + if (PartOfSpeech.includes(gram as Grammeme)) { + return colors.bgBlue; + } + if (NounGrams.includes(gram as Grammeme)) { + return colors.bgGreen; + } + if (VerbGrams.includes(gram as Grammeme)) { + return colors.bgTeal; + } + return colors.bgInput; +} + +/** + * Determines foreground color for {@link GramData}. + */ export function colorfgGrammeme(gram: GramData, colors: IColorTheme): string { if (PartOfSpeech.includes(gram as Grammeme)) { return colors.fgBlue; @@ -401,17 +454,3 @@ export function colorfgGrammeme(gram: GramData, colors: IColorTheme): string { return colors.fgPurple; } } - -export function colorbgGrammeme(gram: GramData, colors: IColorTheme): string { - if (PartOfSpeech.includes(gram as Grammeme)) { - return colors.bgBlue; - } - if (NounGrams.includes(gram as Grammeme)) { - return colors.bgGreen; - } - if (VerbGrams.includes(gram as Grammeme)) { - return colors.bgTeal; - } - return colors.bgInput; -} - diff --git a/rsconcept/frontend/src/utils/constants.ts b/rsconcept/frontend/src/utils/constants.ts index 2c1cc72b..09374c7c 100644 --- a/rsconcept/frontend/src/utils/constants.ts +++ b/rsconcept/frontend/src/utils/constants.ts @@ -1,16 +1,47 @@ -// Constants -export const config = { +/** + * Module: Global constants. + */ + +/** + * Variable constants depending on build type. + */ +export const buidConstants = { backend: import.meta.env.VITE_PORTAL_BACKEND as string }; + +/** + * General UI timeout [in ms] for waiting for render. + */ export const TIMEOUT_UI_REFRESH = 100; + +/** + * Timeout [in ms] for graph refresh. + */ export const TIMEOUT_GRAPH_REFRESH = 200; +/** + * Exteor file extension for RSForm. + */ export const EXTEOR_TRS_FILE = '.trs'; +/** + * Resource relative URIs. + */ +export const resources = { + graph_font: '/DejaVu.ttf' +} + + +/** + * Youtube IDs for embedding. + */ export const youtube = { intro: '0Ty9mu9sOJo' }; +/** + * Constant URLs. + */ export const urls = { concept: 'https://www.acconcept.ru/', exteor32: 'https://drive.google.com/open?id=1IHlMMwaYlAUBRSxU1RU_hXM5mFU9-oyK&usp=drive_fs', @@ -24,14 +55,16 @@ export const urls = { restapi: 'https://api.portal.acconcept.ru' }; -export const resources = { - graph_font: '/DejaVu.ttf' -} - +/** + * Global unique IDs. + */ export const globalIDs = { main_scroll: 'main-scroll' } +/** + * Prefixes for generating unique keys for lists. + */ export const prefixes = { cst_list: 'cst-list-', cst_hidden_list: 'cst-hidden-list-', diff --git a/rsconcept/frontend/src/utils/labels.ts b/rsconcept/frontend/src/utils/labels.ts index ad4fd777..b80e34ee 100644 --- a/rsconcept/frontend/src/utils/labels.ts +++ b/rsconcept/frontend/src/utils/labels.ts @@ -1,10 +1,17 @@ -// =========== Module contains all text descriptors. ========== - +/** + * Module: Text descriptors for UI and model elements. + * + * Label is a short text used to represent an entity. + * Description is a long description used in tooltips. + */ import { GramData,Grammeme, ReferenceType } from '../models/language'; import { CstMatchMode, DependencyMode, HelpTopic, LibraryFilterStrategy } from '../models/miscelanious'; import { CstClass, CstType, ExpressionStatus, IConstituenta } from '../models/rsform'; import { IArgumentInfo, IRSErrorDescription, ISyntaxTreeNode, ParsingStatus, RSErrorType, TokenID } from '../models/rslang'; +/** + * Generates desription for {@link IConstituenta}. + */ export function describeConstituenta(cst: IConstituenta): string { if (cst.cst_type === CstType.STRUCTURED) { return ( @@ -23,7 +30,10 @@ export function describeConstituenta(cst: IConstituenta): string { } } -export function describeConstituentaTerm(cst: IConstituenta | undefined): string { +/** + * Generates desription for term of a given {@link IConstituenta}. + */ +export function describeConstituentaTerm(cst?: IConstituenta): string { if (!cst) { return '!Конституента отсутствует!'; } @@ -34,10 +44,16 @@ export function describeConstituentaTerm(cst: IConstituenta | undefined): string } } +/** + * Generates label for {@link IConstituenta}. + */ export function labelConstituenta(cst: IConstituenta) { return `${cst.alias}: ${describeConstituenta(cst)}`; } +/** + * Retrieves label for {@link TokenID}. + */ export function labelToken(id: TokenID): string { switch (id) { case TokenID.BOOLEAN: return 'ℬ()'; @@ -126,6 +142,9 @@ export function describeToken(id: TokenID): string { return `no description: ${id}`; } +/** + * Retrieves label for {@link CstMatchMode}. + */ export function labelCstMathchMode(mode: CstMatchMode): string { switch (mode) { case CstMatchMode.ALL: return 'общий'; @@ -136,6 +155,9 @@ export function labelCstMathchMode(mode: CstMatchMode): string { } } +/** + * Retrieves description for {@link CstMatchMode}. + */ export function describeCstMathchMode(mode: CstMatchMode): string { switch (mode) { case CstMatchMode.ALL: return 'искать во всех атрибутах'; @@ -146,6 +168,9 @@ export function describeCstMathchMode(mode: CstMatchMode): string { } } +/** + * Retrieves label for {@link DependencyMode}. + */ export function labelCstSource(mode: DependencyMode): string { switch (mode) { case DependencyMode.ALL: return 'не ограничен'; @@ -157,6 +182,9 @@ export function labelCstSource(mode: DependencyMode): string { } } +/** + * Retrieves description for {@link DependencyMode}. + */ export function describeCstSource(mode: DependencyMode): string { switch (mode) { case DependencyMode.ALL: return 'все конституенты'; @@ -168,6 +196,9 @@ export function describeCstSource(mode: DependencyMode): string { } } +/** + * Retrieves label for {@link LibraryFilterStrategy}. + */ export function labelLibraryFilter(strategy: LibraryFilterStrategy): string { switch (strategy) { case LibraryFilterStrategy.MANUAL: return 'отображать все'; @@ -179,6 +210,9 @@ export function labelLibraryFilter(strategy: LibraryFilterStrategy): string { } } +/** + * Retrieves description for {@link LibraryFilterStrategy}. + */ export function describeLibraryFilter(strategy: LibraryFilterStrategy): string { switch (strategy) { case LibraryFilterStrategy.MANUAL: return 'Отображать все схемы'; @@ -190,6 +224,9 @@ export function describeLibraryFilter(strategy: LibraryFilterStrategy): string { } } +/** + * Retrieves label for graph layout mode. + */ export const mapLableLayout: Map = new Map([ ['forceatlas2', 'Граф: Атлас 2D'], @@ -207,6 +244,9 @@ new Map([ ['nooverlap', 'Граф: Без перекрытия'] ]); +/** + * Retrieves label for graph coloring mode. + */ export const mapLabelColoring: Map = new Map([ ['none', 'Цвет: моно'], @@ -214,6 +254,9 @@ new Map([ ['type', 'Цвет: класс'], ]); +/** + * Retrieves label for {@link ExpressionStatus}. + */ export function labelExpressionStatus(status: ExpressionStatus): string { switch (status) { case ExpressionStatus.VERIFIED: return 'корректно'; @@ -225,6 +268,9 @@ export function labelExpressionStatus(status: ExpressionStatus): string { } } +/** + * Retrieves description for {@link ExpressionStatus}. + */ export function describeExpressionStatus(status: ExpressionStatus): string { switch (status) { case ExpressionStatus.VERIFIED: return 'выражение корректно и вычислимо'; @@ -236,6 +282,9 @@ export function describeExpressionStatus(status: ExpressionStatus): string { } } +/** + * Retrieves label for {@link HelpTopic}. + */ export function labelHelpTopic(topic: HelpTopic): string { switch (topic) { case HelpTopic.MAIN: return 'Портал'; @@ -252,6 +301,9 @@ export function labelHelpTopic(topic: HelpTopic): string { } } +/** + * Retrieves description for {@link HelpTopic}. + */ export function describeHelpTopic(topic: HelpTopic): string { switch (topic) { case HelpTopic.MAIN: return 'Общая справка по порталу'; @@ -268,6 +320,9 @@ export function describeHelpTopic(topic: HelpTopic): string { } } +/** + * Retrieves label for {@link CstType}. + */ export function labelCstType(type: CstType): string { switch (type) { case CstType.BASE: return 'Базисное множество'; @@ -281,6 +336,9 @@ export function labelCstType(type: CstType): string { } } +/** + * Retrieves label for {@link ReferenceType}. + */ export function labelReferenceType(type: ReferenceType): string { switch(type) { case ReferenceType.ENTITY: return 'Использование термина'; @@ -288,6 +346,9 @@ export function labelReferenceType(type: ReferenceType): string { } } +/** + * Retrieves label for {@link CstClass}. + */ export function labelCstClass(cclass: CstClass): string { switch (cclass) { case CstClass.BASIC: return 'базовый'; @@ -297,6 +358,9 @@ export function labelCstClass(cclass: CstClass): string { } } +/** + * Retrieves description for {@link CstClass}. + */ export function describeCstClass(cclass: CstClass): string { switch (cclass) { case CstClass.BASIC: return 'неопределяемое понятие, требует конвенции'; @@ -306,6 +370,9 @@ export function describeCstClass(cclass: CstClass): string { } } +/** + * Generates label for typification. + */ export function labelTypification({ isValid, resultType, args }: { isValid: boolean; resultType: string; @@ -332,6 +399,9 @@ export function labelCstTypification(cst: IConstituenta): string { }); } +/** + * Generates label for {@link ISyntaxTreeNode}. + */ export function labelSyntaxTree(node: ISyntaxTreeNode): string { switch (node.typeID) { case TokenID.ID_LOCAL: @@ -481,6 +551,9 @@ export function labelGrammeme(gram: GramData): string { } } +/** + * Generates error description for {@link IRSErrorDescription}. + */ export function describeRSError(error: IRSErrorDescription): string { switch (error.errorType) { case RSErrorType.unknownSymbol: diff --git a/rsconcept/frontend/src/utils/misc.ts b/rsconcept/frontend/src/utils/misc.ts index 8e093b5b..9c55fa60 100644 --- a/rsconcept/frontend/src/utils/misc.ts +++ b/rsconcept/frontend/src/utils/misc.ts @@ -1,9 +1,10 @@ - -// Module: miscellaneous static functions to generate UI resources +/** + * Module: miscellaneous static functions to generate UI resources. + */ import { CstType, IConstituenta, IRSForm } from '../models/rsform'; -import { IRSErrorDescription } from '../models/rslang'; -import { resolveErrorClass, RSErrorClass } from '../models/rslang'; +import { IRSErrorDescription, RSErrorClass } from '../models/rslang'; +import { inferErrorClass } from '../models/rslangAPI'; import { labelCstType } from './labels'; export function getCstTypePrefix(type: CstType) { @@ -70,7 +71,7 @@ export function cloneTitle(schema: IRSForm): string { export function getRSErrorPrefix(error: IRSErrorDescription): string { const id = error.errorType.toString(16) - switch(resolveErrorClass(error.errorType)) { + switch(inferErrorClass(error.errorType)) { case RSErrorClass.LEXER: return 'L' + id; case RSErrorClass.PARSER: return 'P' + id; case RSErrorClass.SEMANTIC: return 'S' + id; diff --git a/rsconcept/frontend/src/utils/selectors.ts b/rsconcept/frontend/src/utils/selectors.ts index 352ab492..09ccaf32 100644 --- a/rsconcept/frontend/src/utils/selectors.ts +++ b/rsconcept/frontend/src/utils/selectors.ts @@ -1,4 +1,6 @@ -// Module: Selector maps +/** + * Module: Mappings for selector UI elements. + */ import { LayoutTypes } from 'reagraph'; import { type GramData, Grammeme, ReferenceType } from '../models/language'; diff --git a/rsconcept/frontend/src/utils/utils.tsx b/rsconcept/frontend/src/utils/utils.tsx index 926a209d..93ac1c2b 100644 --- a/rsconcept/frontend/src/utils/utils.tsx +++ b/rsconcept/frontend/src/utils/utils.tsx @@ -1,6 +1,13 @@ +/** + * Module: Utility functions. + */ + +/** + * Checks if arguments is Node. + */ export function assertIsNode(e: EventTarget | null): asserts e is Node { - if (!e || !('nodeType' in e)) { - throw new Error('Node expected'); + if (e === null || !('nodeType' in e)) { + throw new TypeError(`Expected 'Node' but recieved '${e?.constructor.name ?? 'null'}'`); } }