From c322e2e8ebe2ed9d795410946afef7366eb3653b Mon Sep 17 00:00:00 2001 From: IRBorisov <8611739+IRBorisov@users.noreply.github.com> Date: Thu, 21 Sep 2023 14:58:01 +0300 Subject: [PATCH] Refactor UI labels --- README.md | 1 + rsconcept/frontend/.eslintrc.json | 7 +- rsconcept/frontend/package-lock.json | 48 ++ rsconcept/frontend/package.json | 1 + .../src/components/Help/HelpRSLang.tsx | 8 +- .../src/components/Help/InfoConstituenta.tsx | 4 +- .../src/components/Help/InfoCstClass.tsx | 14 +- .../src/components/Help/InfoCstStatus.tsx | 14 +- .../src/components/RSInput/tooltip.ts | 4 +- .../frontend/src/hooks/useCheckExpression.ts | 2 +- .../frontend/src/models/language.test.ts | 20 + rsconcept/frontend/src/models/language.ts | 96 ++- rsconcept/frontend/src/models/rsform.ts | 27 + .../src/pages/ManualsPage/TopicsList.tsx | 10 +- .../src/pages/RSFormPage/DlgCloneRSForm.tsx | 4 +- .../src/pages/RSFormPage/DlgCreateCst.tsx | 4 +- .../src/pages/RSFormPage/DlgDeleteCst.tsx | 6 +- .../src/pages/RSFormPage/DlgEditTerm.tsx | 165 +++- .../src/pages/RSFormPage/DlgGraphOptions.tsx | 18 +- .../src/pages/RSFormPage/DlgRenameCst.tsx | 5 +- .../src/pages/RSFormPage/DlgShowAST.tsx | 7 +- .../pages/RSFormPage/EditorConstituenta.tsx | 4 +- .../src/pages/RSFormPage/EditorItems.tsx | 13 +- .../pages/RSFormPage/EditorRSExpression.tsx | 81 +- .../src/pages/RSFormPage/EditorTermGraph.tsx | 15 +- .../frontend/src/pages/RSFormPage/RSTabs.tsx | 2 +- .../elements/DependencyModePicker.tsx | 4 +- .../RSFormPage/elements/MatchModePicker.tsx | 4 +- .../RSFormPage/elements/ParsingResult.tsx | 5 +- .../RSFormPage/elements/RSTokenButton.tsx | 16 +- .../pages/RSFormPage/elements/StatusBar.tsx | 10 +- .../elements/ViewSideConstituents.tsx | 12 +- rsconcept/frontend/src/utils/Graph.ts | 9 +- rsconcept/frontend/src/utils/color.ts | 115 +++ rsconcept/frontend/src/utils/labels.ts | 514 ++++++++++++ rsconcept/frontend/src/utils/misc.ts | 72 ++ rsconcept/frontend/src/utils/selectors.ts | 81 +- rsconcept/frontend/src/utils/staticUI.ts | 740 ------------------ scripts/prod/UpdateProd.sh | 12 +- 39 files changed, 1227 insertions(+), 947 deletions(-) create mode 100644 rsconcept/frontend/src/models/language.test.ts create mode 100644 rsconcept/frontend/src/utils/labels.ts create mode 100644 rsconcept/frontend/src/utils/misc.ts delete mode 100644 rsconcept/frontend/src/utils/staticUI.ts diff --git a/README.md b/README.md index efbd4bc8..0aa2914b 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ This readme file is used mostly to document project dependencies
   - tailwindcss postcss autoprefixer
   - eslint-plugin-simple-import-sort
+  - eslint-plugin-tsdoc
   - jest
   - ts-jest
   - @types/jest
diff --git a/rsconcept/frontend/.eslintrc.json b/rsconcept/frontend/.eslintrc.json
index 8ee1faf7..7fbc22f0 100644
--- a/rsconcept/frontend/.eslintrc.json
+++ b/rsconcept/frontend/.eslintrc.json
@@ -15,13 +15,16 @@
         "project": ["tsconfig.json", "tsconfig.node.json"]
     },
     "plugins": [
-        "react-refresh", "simple-import-sort"
+        "react-refresh",
+        "simple-import-sort",
+        "eslint-plugin-tsdoc"
     ],
     "rules": {
         "react-refresh/only-export-components": [
             "off",
             { "allowConstantExport": true }
         ],
-        "simple-import-sort/imports": "warn"
+        "simple-import-sort/imports": "warn",
+        "tsdoc/syntax": "warn"
     }
 }
diff --git a/rsconcept/frontend/package-lock.json b/rsconcept/frontend/package-lock.json
index a1a3d6e3..320cdc94 100644
--- a/rsconcept/frontend/package-lock.json
+++ b/rsconcept/frontend/package-lock.json
@@ -40,6 +40,7 @@
         "eslint-plugin-react-hooks": "^4.6.0",
         "eslint-plugin-react-refresh": "^0.4.3",
         "eslint-plugin-simple-import-sort": "^10.0.0",
+        "eslint-plugin-tsdoc": "^0.2.17",
         "jest": "^29.6.4",
         "postcss": "^8.4.29",
         "tailwindcss": "^3.3.3",
@@ -2228,6 +2229,37 @@
       "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.2.tgz",
       "integrity": "sha512-d8Q9uRK89ZRWmED2JLI9/blpJcfdbh0iEUuMo8TgkMzNfQBY1/GC0FEJWrairTwHkxIf6Oud1vFBP+aHicWqJA=="
     },
+    "node_modules/@microsoft/tsdoc": {
+      "version": "0.14.2",
+      "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz",
+      "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==",
+      "dev": true
+    },
+    "node_modules/@microsoft/tsdoc-config": {
+      "version": "0.16.2",
+      "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz",
+      "integrity": "sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==",
+      "dev": true,
+      "dependencies": {
+        "@microsoft/tsdoc": "0.14.2",
+        "ajv": "~6.12.6",
+        "jju": "~1.4.0",
+        "resolve": "~1.19.0"
+      }
+    },
+    "node_modules/@microsoft/tsdoc-config/node_modules/resolve": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
+      "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
+      "dev": true,
+      "dependencies": {
+        "is-core-module": "^2.1.0",
+        "path-parse": "^1.0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -4252,6 +4284,16 @@
         "eslint": ">=5.0.0"
       }
     },
+    "node_modules/eslint-plugin-tsdoc": {
+      "version": "0.2.17",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.17.tgz",
+      "integrity": "sha512-xRmVi7Zx44lOBuYqG8vzTXuL6IdGOeF9nHX17bjJ8+VE6fsxpdGem0/SBTmAwgYMKYB1WBkqRJVQ+n8GK041pA==",
+      "dev": true,
+      "dependencies": {
+        "@microsoft/tsdoc": "0.14.2",
+        "@microsoft/tsdoc-config": "0.16.2"
+      }
+    },
     "node_modules/eslint-scope": {
       "version": "7.2.2",
       "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
@@ -6837,6 +6879,12 @@
         "jiti": "bin/jiti.js"
       }
     },
+    "node_modules/jju": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz",
+      "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==",
+      "dev": true
+    },
     "node_modules/js-file-download": {
       "version": "0.4.12",
       "resolved": "https://registry.npmjs.org/js-file-download/-/js-file-download-0.4.12.tgz",
diff --git a/rsconcept/frontend/package.json b/rsconcept/frontend/package.json
index c4d2ba96..b4915909 100644
--- a/rsconcept/frontend/package.json
+++ b/rsconcept/frontend/package.json
@@ -44,6 +44,7 @@
     "eslint-plugin-react-hooks": "^4.6.0",
     "eslint-plugin-react-refresh": "^0.4.3",
     "eslint-plugin-simple-import-sort": "^10.0.0",
+    "eslint-plugin-tsdoc": "^0.2.17",
     "jest": "^29.6.4",
     "postcss": "^8.4.29",
     "tailwindcss": "^3.3.3",
diff --git a/rsconcept/frontend/src/components/Help/HelpRSLang.tsx b/rsconcept/frontend/src/components/Help/HelpRSLang.tsx
index ddc84741..9d3611b3 100644
--- a/rsconcept/frontend/src/components/Help/HelpRSLang.tsx
+++ b/rsconcept/frontend/src/components/Help/HelpRSLang.tsx
@@ -19,14 +19,14 @@ function HelpRSLang() {
   return (
     
-

Язык родов структур

+

Родоструктурная экспликация концептуальных схем

Формальная запись (экспликация) концептуальных схем осуществляется с помощью языка родов структур.

Данный математический аппарат основан на аксиоматической теории множеств Цермелло-Френкеля и аппарате родов структур Н.Бурбаки.

Для ознакомления с основами родов структур можно использовать следующие материалы:

diff --git a/rsconcept/frontend/src/components/Help/InfoConstituenta.tsx b/rsconcept/frontend/src/components/Help/InfoConstituenta.tsx index ce1b816a..975ce9f1 100644 --- a/rsconcept/frontend/src/components/Help/InfoConstituenta.tsx +++ b/rsconcept/frontend/src/components/Help/InfoConstituenta.tsx @@ -1,5 +1,5 @@ import { IConstituenta } from '../../models/rsform'; -import { getCstTypificationLabel } from '../../utils/staticUI'; +import { labelCstTypification } from '../../utils/labels'; interface InfoConstituentaProps extends React.HTMLAttributes { @@ -10,7 +10,7 @@ function InfoConstituenta({ data, ...props }: InfoConstituentaProps) { return (

Конституента {data.alias}

-

Типизация: {getCstTypificationLabel(data)}

+

Типизация: {labelCstTypification(data)}

Термин: {data.term_resolved || data.term_raw}

{data.definition_formal &&

Выражение: {data.definition_formal}

} {data.definition_resolved &&

Определение: {data.definition_resolved}

} diff --git a/rsconcept/frontend/src/components/Help/InfoCstClass.tsx b/rsconcept/frontend/src/components/Help/InfoCstClass.tsx index d63fce3e..9c9b94d5 100644 --- a/rsconcept/frontend/src/components/Help/InfoCstClass.tsx +++ b/rsconcept/frontend/src/components/Help/InfoCstClass.tsx @@ -1,6 +1,8 @@ import { useConceptTheme } from '../../context/ThemeContext'; +import { CstClass } from '../../models/rsform'; +import { colorbgCstClass } from '../../utils/color'; import { prefixes } from '../../utils/constants'; -import { getCstClassColor, mapCstClassInfo } from '../../utils/staticUI'; +import { describeCstClass, labelCstClass } from '../../utils/labels'; interface InfoCstClassProps { title?: string @@ -12,19 +14,19 @@ function InfoCstClass({ title }: InfoCstClassProps) { return (
{ title &&

{title}

} - { [... mapCstClassInfo.entries()].map( - ([cstClass, info], index) => { + { Object.values(CstClass).map( + (cclass, index) => { return (

- {info.text} + {labelCstClass(cclass)} - - {info.tooltip} + {describeCstClass(cclass)}

); })} diff --git a/rsconcept/frontend/src/components/Help/InfoCstStatus.tsx b/rsconcept/frontend/src/components/Help/InfoCstStatus.tsx index c9944c6a..78098b33 100644 --- a/rsconcept/frontend/src/components/Help/InfoCstStatus.tsx +++ b/rsconcept/frontend/src/components/Help/InfoCstStatus.tsx @@ -1,6 +1,8 @@ import { useConceptTheme } from '../../context/ThemeContext'; +import { ExpressionStatus } from '../../models/rsform'; +import { colorbgCstStatus } from '../../utils/color'; import { prefixes } from '../../utils/constants'; -import { getCstStatusBgColor, mapStatusInfo } from '../../utils/staticUI'; +import { describeExpressionStatus, labelExpressionStatus } from '../../utils/labels'; interface InfoCstStatusProps { title?: string @@ -12,19 +14,19 @@ function InfoCstStatus({ title }: InfoCstStatusProps) { return (
{ title &&

{title}

} - { [... mapStatusInfo.entries()].map( - ([status, info], index) => { + { Object.values(ExpressionStatus).map( + (status, index) => { return (

- {info.text} + {labelExpressionStatus(status)} - - {info.tooltip} + {describeExpressionStatus(status)}

); })} diff --git a/rsconcept/frontend/src/components/RSInput/tooltip.ts b/rsconcept/frontend/src/components/RSInput/tooltip.ts index e645d98e..42e546cc 100644 --- a/rsconcept/frontend/src/components/RSInput/tooltip.ts +++ b/rsconcept/frontend/src/components/RSInput/tooltip.ts @@ -2,13 +2,13 @@ import { Extension } from '@codemirror/state'; import { hoverTooltip } from '@codemirror/view'; import { IConstituenta } from '../../models/rsform'; -import { getCstTypificationLabel } from '../../utils/staticUI'; +import { labelCstTypification } from '../../utils/labels'; function createTooltipFor(cst: IConstituenta) { const dom = document.createElement('div'); dom.className = 'overflow-y-auto border shadow-md max-h-[25rem] max-w-[25rem] min-w-[10rem] w-fit z-tooltip text-sm px-2 py-2'; const alias = document.createElement('p'); - alias.innerHTML = `${cst.alias}: ${getCstTypificationLabel(cst)}`; + alias.innerHTML = `${cst.alias}: ${labelCstTypification(cst)}`; dom.appendChild(alias); if (cst.term_resolved) { const term = document.createElement('p'); diff --git a/rsconcept/frontend/src/hooks/useCheckExpression.ts b/rsconcept/frontend/src/hooks/useCheckExpression.ts index 736688d8..41e0cde5 100644 --- a/rsconcept/frontend/src/hooks/useCheckExpression.ts +++ b/rsconcept/frontend/src/hooks/useCheckExpression.ts @@ -5,7 +5,7 @@ import { CstType, IConstituenta, type IRSForm } from '../models/rsform'; import { IExpressionParse, IFunctionArg } from '../models/rslang'; import { RSErrorType } from '../models/rslang'; import { DataCallback, postCheckExpression } from '../utils/backendAPI'; -import { getCstExpressionPrefix } from '../utils/staticUI'; +import { getCstExpressionPrefix } from '../utils/misc'; const LOGIC_TYPIIFCATION = 'LOGIC'; diff --git a/rsconcept/frontend/src/models/language.test.ts b/rsconcept/frontend/src/models/language.test.ts new file mode 100644 index 00000000..38db0f25 --- /dev/null +++ b/rsconcept/frontend/src/models/language.test.ts @@ -0,0 +1,20 @@ +import { Grammeme, parseGrammemes } from './language'; + + +describe('Testing grammeme parsing', () => { + test('empty input', + () => { + expect(parseGrammemes('').length).toBe(0); + expect(parseGrammemes(' ').length).toBe(0); + expect(parseGrammemes(' , ').length).toBe(0); + }); + + test('regular grammemes', + () => { + expect(parseGrammemes('NOUN')).toStrictEqual([{type: Grammeme.NOUN, data: 'NOUN'}]); + expect(parseGrammemes('sing,nomn')).toStrictEqual([ + {type: Grammeme.sing, data: 'sing'}, + {type: Grammeme.nomn, data: 'nomn'} + ]); + }); +}); diff --git a/rsconcept/frontend/src/models/language.ts b/rsconcept/frontend/src/models/language.ts index f30a498c..cb687616 100644 --- a/rsconcept/frontend/src/models/language.ts +++ b/rsconcept/frontend/src/models/language.ts @@ -3,6 +3,9 @@ // ====== Morphology ======== export enum Grammeme { + // Неизвестная граммема + UNKN = 'UNKN', + // Части речи NOUN = 'NOUN', ADJF = 'ADJF', @@ -21,7 +24,6 @@ export enum Grammeme { CONJ = 'CONJ', PRCL = 'PRCL', INTJ = 'INTJ', - PNCT = 'PNCT', // Одушевленность anim = 'anim', @@ -88,8 +90,7 @@ export const PartOfSpeech = [ Grammeme.NOUN, Grammeme.ADJF, Grammeme.ADJS, Grammeme.COMP, Grammeme.VERB, Grammeme.INFN, Grammeme.PRTF, Grammeme.PRTS, Grammeme.GRND, Grammeme.ADVB, Grammeme.NPRO, Grammeme.PRED, - Grammeme.PREP, Grammeme.CONJ, Grammeme.PRCL, Grammeme.INTJ, - Grammeme.PNCT + Grammeme.PREP, Grammeme.CONJ, Grammeme.PRCL, Grammeme.INTJ ]; export const Gender = [ @@ -101,6 +102,94 @@ export const Case = [ Grammeme.accs, Grammeme.ablt, Grammeme.loct ]; +export const Plurality = [ Grammeme.sing, Grammeme.plur ]; + +export const Perfectivity = [ Grammeme.perf, Grammeme.impf ]; +export const Transitivity = [ Grammeme.tran, Grammeme.intr ]; +export const Mood = [ Grammeme.indc, Grammeme.impr ]; +export const Inclusion = [ Grammeme.incl, Grammeme.excl ]; +export const Voice = [ Grammeme.actv, Grammeme.pssv ]; + +export const Tense = [ + Grammeme.pres, + Grammeme.past, + Grammeme.futr +]; + +export const Person = [ + Grammeme.per1, + Grammeme.per2, + Grammeme.per3 +]; + +export const GrammemeGroups = [ + PartOfSpeech, Gender, Case, Plurality, Perfectivity, + Transitivity, Mood, Inclusion, Voice, Tense, Person +]; + +export const NounGrams = [ + Grammeme.NOUN, Grammeme.ADJF, Grammeme.ADJS, + ...Gender, + ...Case, + ...Plurality +]; + +export const VerbGrams = [ + Grammeme.VERB, Grammeme.INFN, Grammeme.PRTF, Grammeme.PRTS, + ...Perfectivity, + ...Transitivity, + ...Mood, + ...Inclusion, + ...Voice, + ...Tense, + ...Person +]; + +// Grammeme parse data +export interface IGramData { + type: Grammeme + data: string +} + +// Equality comparator for IGramData +export function matchGrammeme(value: IGramData, test: IGramData): boolean { + if (value.type !== test.type) { + return false; + } + return value.type !== Grammeme.UNKN || value.data === test.data; +} + +function parseSingleGrammeme(text: string): IGramData { + if (Object.values(Grammeme).includes(text as Grammeme)) { + return { + data: text, + type: text as Grammeme + } + } else { + return { + data: text, + type: Grammeme.UNKN + } + } +} + +export function parseGrammemes(termForm: string): IGramData[] { + const result: IGramData[] = []; + const chunks = termForm.split(','); + chunks.forEach(chunk => { + chunk = chunk.trim(); + if (chunk !== '') { + result.push(parseSingleGrammeme(chunk)); + } + }); + return result; +} + +export interface IWordForm { + text: string + grams: IGramData[] +} + // ====== Reference resolution ===== export interface IRefsText { text: string @@ -110,6 +199,7 @@ export enum ReferenceType { ENTITY = 'entity', SYNTACTIC = 'syntax' } + export interface IEntityReference { entity: string form: string diff --git a/rsconcept/frontend/src/models/rsform.ts b/rsconcept/frontend/src/models/rsform.ts index 597ae5fa..b34548cd 100644 --- a/rsconcept/frontend/src/models/rsform.ts +++ b/rsconcept/frontend/src/models/rsform.ts @@ -274,3 +274,30 @@ export function inferClass(type: CstType, isTemplate: boolean): CstClass { } } +export function createMockConstituenta(schema: number, id: number, alias: string, type: CstType, comment: string): IConstituenta { + return { + id: id, + order: -1, + schema: schema, + alias: alias, + convention: comment, + cst_type: type, + term_raw: '', + term_resolved: '', + term_forms: [], + definition_formal: '', + definition_raw: '', + definition_resolved: '', + status: ExpressionStatus.INCORRECT, + is_template: false, + cst_class: CstClass.DERIVED, + parse: { + status: ParsingStatus.INCORRECT, + valueClass: ValueClass.INVALID, + typification: 'N/A', + syntaxTree: '', + args: [] + } + }; +} + diff --git a/rsconcept/frontend/src/pages/ManualsPage/TopicsList.tsx b/rsconcept/frontend/src/pages/ManualsPage/TopicsList.tsx index 64bc62ed..5623e6af 100644 --- a/rsconcept/frontend/src/pages/ManualsPage/TopicsList.tsx +++ b/rsconcept/frontend/src/pages/ManualsPage/TopicsList.tsx @@ -1,6 +1,6 @@ import { HelpTopic } from '../../models/miscelanious'; import { prefixes } from '../../utils/constants'; -import { mapTopicInfo } from '../../utils/staticUI'; +import { describeHelpTopic, labelHelpTopic } from '../../utils/labels'; interface TopicsListProps { activeTopic: HelpTopic @@ -11,15 +11,15 @@ function TopicsList({ activeTopic, onChangeTopic }: TopicsListProps) { return (
Справка
- { [... mapTopicInfo.entries()].map( - ([topic, info], index) => { + { Object.values(HelpTopic).map( + (topic, index) => { return (
onChangeTopic(topic)} > - {info.text} + {labelHelpTopic(topic)}
) })}
diff --git a/rsconcept/frontend/src/pages/RSFormPage/DlgCloneRSForm.tsx b/rsconcept/frontend/src/pages/RSFormPage/DlgCloneRSForm.tsx index 1ffd8593..2bae659c 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/DlgCloneRSForm.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/DlgCloneRSForm.tsx @@ -9,7 +9,7 @@ import { useLibrary } from '../../context/LibraryContext'; import { useConceptNavigation } from '../../context/NagivationContext'; import { useRSForm } from '../../context/RSFormContext'; import { IRSFormCreateData } from '../../models/rsform'; -import { getCloneTitle } from '../../utils/staticUI'; +import { cloneTitle } from '../../utils/misc'; interface DlgCloneRSFormProps extends Pick {} @@ -27,7 +27,7 @@ function DlgCloneRSForm({ hideWindow }: DlgCloneRSFormProps) { useEffect(() => { if (schema) { - setTitle(getCloneTitle(schema)); + setTitle(cloneTitle(schema)); setAlias(schema.alias); setComment(schema.comment); setCommon(schema.is_common); diff --git a/rsconcept/frontend/src/pages/RSFormPage/DlgCreateCst.tsx b/rsconcept/frontend/src/pages/RSFormPage/DlgCreateCst.tsx index 03bb9660..58a1a28d 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/DlgCreateCst.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/DlgCreateCst.tsx @@ -6,7 +6,7 @@ import TextArea from '../../components/Common/TextArea'; import RSInput from '../../components/RSInput'; import { CstType,ICstCreateData } from '../../models/rsform'; import { SelectorCstType } from '../../utils/selectors'; -import { getCstTypeLabel } from '../../utils/staticUI'; +import { labelCstType } from '../../utils/labels'; interface DlgCreateCstProps extends Pick { @@ -62,7 +62,7 @@ function DlgCreateCst({ hideWindow, initial, onCreate }: DlgCreateCstProps) { className='my-2 min-w-[15rem] self-center' options={SelectorCstType} placeholder='Выберите тип' - value={selectedType ? { value: selectedType, label: getCstTypeLabel(selectedType) } : null} + value={selectedType ? { value: selectedType, label: labelCstType(selectedType) } : null} onChange={data => setSelectedType(data?.value ?? CstType.BASE)} />
diff --git a/rsconcept/frontend/src/pages/RSFormPage/DlgDeleteCst.tsx b/rsconcept/frontend/src/pages/RSFormPage/DlgDeleteCst.tsx index 75177789..0c89c796 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/DlgDeleteCst.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/DlgDeleteCst.tsx @@ -3,7 +3,7 @@ import { useMemo, useState } from 'react'; import Checkbox from '../../components/Common/Checkbox'; import Modal, { ModalProps } from '../../components/Common/Modal'; import { useRSForm } from '../../context/RSFormContext'; -import { getCstLabel } from '../../utils/staticUI'; +import { labelConstituenta } from '../../utils/labels'; interface DlgDeleteCstProps extends Pick { @@ -39,14 +39,14 @@ function DlgDeleteCst({ hideWindow, selected, onDelete }: DlgDeleteCstProps) {
{selected.map(id => { const cst = schema!.items.find(cst => cst.id === id); - return (cst &&

{getCstLabel(cst)}

); + return (cst &&

{labelConstituenta(cst)}

); })}

Зависимые конституенты: {expansion.length}

{expansion.map(id => { const cst = schema!.items.find(cst => cst.id === id); - return (cst &&

{getCstLabel(cst)}

); + return (cst &&

{labelConstituenta(cst)}

); })}
void target: IConstituenta - onSave: () => void + onSave: (data: TermForm[]) => void } +const columnHelper = createColumnHelper(); + function DlgEditTerm({ hideWindow, target, onSave }: DlgEditTermProps) { const [term, setTerm] = useState(''); const [inputText, setInputText] = useState(''); - const [inputTags, setInputTags] = useState<{ value: Grammeme, label: string }[]>([]); + const [inputGrams, setInputGrams] = useState([]); + const [options, setOptions] = useState([]); + const [forms, setForms] = useState([]); - - // function getData() { - // return { + function getData(): TermForm[] { + const result: TermForm[] = []; + forms.forEach( + ({text, grams}) => result.push({ + text: text, + tags: grams.join(',') + })); + return result; + } - // }; - // } + // Initialization + useLayoutEffect( + () => { + const initForms: IWordForm[] = []; + target.term_forms.forEach( + term => initForms.push({ + text: term.text, + grams: parseGrammemes(term.tags), + })); + setForms(initForms); + setTerm(target.term_resolved); + }, [target]); - const handleSubmit = () => onSave(); // getData() + // Filter grammemes when input changes + useEffect( + () => { + let newFilter: Grammeme[] = []; + inputGrams.forEach(({value: gram}) => { + if (!newFilter.includes(gram)) { + if (NounGrams.includes(gram)) { + newFilter.push(...NounGrams); + } + if (VerbGrams.includes(gram)) { + newFilter.push(...NounGrams); + } + } + }); + + inputGrams.forEach(({value: gram}) => + GrammemeGroups.forEach(group => { + if (group.includes(gram)) { + newFilter = newFilter.filter(item => !group.includes(item) || item === gram); + } + })); + + newFilter.push(...inputGrams.map(({value: gram}) => gram)); + if (newFilter.length === 0) { + newFilter = [...VerbGrams, ...NounGrams]; + } + + newFilter = [... new Set(newFilter)]; + setOptions(SelectorGrammems.filter(({value: gram}) => newFilter.includes(gram))); + }, [inputGrams]); + + const handleSubmit = () => onSave(getData()); function handleAddForm() { - + setForms(forms => [ + ...forms, + { + text: inputText, + grams: inputGrams.map(item => ({ + type: item.value, data: item.value as string + })) + } + ]); } function handleResetForm() { @@ -48,10 +109,56 @@ function DlgEditTerm({ hideWindow, target, onSave }: DlgEditTermProps) { } - useLayoutEffect( - () => { - setTerm(target.term_resolved); - }, [target]); + const columns = useMemo( + () => [ + columnHelper.accessor('text', { + id: 'text', + header: 'Текст', + size: 350, + minSize: 350, + maxSize: 350 + }), + columnHelper.accessor('grams', { + id: 'grams', + header: 'Граммемы', + size: 250, + minSize: 250, + maxSize: 250, + cell: props => { + return ( +
+ { props.getValue().map( + data => (<> +
+ {labelGrammeme(data)} +
+ {/* */} + ))} +
); + } + + // cell: props => + //
+ // {props.getValue()} + //
+ }), + // columnHelper.accessor(, { + + // }) + ], []); return ( setInputTags(data.map(value => value))} + value={inputGrams} + onChange={data => setInputGrams(data.map(value => value))} />
-
- Таблица + +
+ +

Список пуст

+ + } + + // onRowDoubleClicked={handleDoubleClick} + // onRowClicked={handleRowClicked} + />
); diff --git a/rsconcept/frontend/src/pages/RSFormPage/DlgGraphOptions.tsx b/rsconcept/frontend/src/pages/RSFormPage/DlgGraphOptions.tsx index afea856a..274aab38 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/DlgGraphOptions.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/DlgGraphOptions.tsx @@ -3,7 +3,7 @@ import { useLayoutEffect, useState } from 'react'; import Checkbox from '../../components/Common/Checkbox'; import Modal, { ModalProps } from '../../components/Common/Modal'; import { CstType } from '../../models/rsform'; -import { getCstTypeLabel } from '../../utils/staticUI'; +import { labelCstType } from '../../utils/labels'; import { GraphEditorParams } from './EditorTermGraph'; interface DlgGraphOptionsProps @@ -105,42 +105,42 @@ function DlgGraphOptions({ hideWindow, initial, onConfirm }:DlgGraphOptionsProps

Типы конституент

setAllowBase(value) } /> setAllowStruct(value) } /> setAllowTerm(value) } /> setAllowAxiom(value) } /> setAllowFunction(value) } /> setAllowPredicate(value) } /> setAllowConstant(value) } /> setAllowTheorem(value) } /> diff --git a/rsconcept/frontend/src/pages/RSFormPage/DlgRenameCst.tsx b/rsconcept/frontend/src/pages/RSFormPage/DlgRenameCst.tsx index e5b444e3..dcdb4213 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/DlgRenameCst.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/DlgRenameCst.tsx @@ -6,7 +6,8 @@ import TextInput from '../../components/Common/TextInput'; import { useRSForm } from '../../context/RSFormContext'; import { CstType, ICstRenameData } from '../../models/rsform'; import { SelectorCstType } from '../../utils/selectors'; -import { createAliasFor, getCstTypeLabel, getCstTypePrefix } from '../../utils/staticUI'; +import { createAliasFor, getCstTypePrefix } from '../../utils/misc'; +import { labelCstType } from '../../utils/labels'; interface DlgRenameCstProps extends Pick { @@ -72,7 +73,7 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) { className='min-w-[14rem] self-center z-modal-top' options={SelectorCstType} placeholder='Выберите тип' - value={cstType ? { value: cstType, label: getCstTypeLabel(cstType) } : null} + value={cstType ? { value: cstType, label: labelCstType(cstType) } : null} onChange={data => setCstType(data?.value ?? CstType.BASE)} />
diff --git a/rsconcept/frontend/src/pages/RSFormPage/DlgShowAST.tsx b/rsconcept/frontend/src/pages/RSFormPage/DlgShowAST.tsx index 6f5118f8..e06e80d8 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/DlgShowAST.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/DlgShowAST.tsx @@ -5,8 +5,9 @@ import Modal, { ModalProps } from '../../components/Common/Modal'; import { useConceptTheme } from '../../context/ThemeContext'; import { SyntaxTree } from '../../models/rslang'; import { graphDarkT, graphLightT } from '../../utils/color'; +import { colorbgSyntaxTree } from '../../utils/color'; import { resources } from '../../utils/constants'; -import { getASTNodeColor, getASTNodeLabel } from '../../utils/staticUI'; +import { labelSyntaxTree } from '../../utils/labels'; interface DlgShowASTProps extends Pick { @@ -24,8 +25,8 @@ function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) { const nodes: GraphNode[] = useMemo( () => syntaxTree.map(node => ({ id: String(node.uid), - label: getASTNodeLabel(node), - fill: getASTNodeColor(node, colors), + label: labelSyntaxTree(node), + fill: colorbgSyntaxTree(node, colors), })), [syntaxTree, colors]); const edges: GraphEdge[] = useMemo( diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx index 01dde3c7..0e7c1d4a 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx @@ -13,7 +13,7 @@ import useWindowSize from '../../hooks/useWindowSize'; import { EditMode } from '../../models/miscelanious'; import { CstType, IConstituenta, ICstCreateData, ICstRenameData, ICstUpdateData } from '../../models/rsform'; import { SyntaxTree } from '../../models/rslang'; -import { getCstTypificationLabel } from '../../utils/staticUI'; +import { labelCstTypification } from '../../utils/labels'; import EditorRSExpression from './EditorRSExpression'; import ViewSideConstituents from './elements/ViewSideConstituents'; @@ -78,7 +78,7 @@ function EditorConstituenta({ setTerm(activeCst.term_raw || ''); setTextDefinition(activeCst.definition_raw || ''); setExpression(activeCst.definition_formal || ''); - setTypification(activeCst ? getCstTypificationLabel(activeCst) : 'N/A'); + setTypification(activeCst ? labelCstTypification(activeCst) : 'N/A'); } }, [activeCst, onOpenEdit, schema]); diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorItems.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorItems.tsx index a26b6a4e..04c9fcbb 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorItems.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorItems.tsx @@ -11,8 +11,10 @@ import { useRSForm } from '../../context/RSFormContext'; import { useConceptTheme } from '../../context/ThemeContext'; import useWindowSize from '../../hooks/useWindowSize'; import { CstType, IConstituenta, ICstCreateData, ICstMovetoData } from '../../models/rsform' +import { colorfgCstStatus } from '../../utils/color'; import { prefixes } from '../../utils/constants'; -import { getCstStatusFgColor, getCstTypePrefix, getCstTypeShortcut, getCstTypificationLabel, mapStatusInfo } from '../../utils/staticUI'; +import { describeExpressionStatus, labelCstTypification } from '../../utils/labels'; +import { getCstTypePrefix, getCstTypeShortcut } from '../../utils/misc'; // Window width cutoff for columns const COLUMN_DEFINITION_HIDE_THRESHOLD = 1000; @@ -221,15 +223,14 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps) maxSize: 65, cell: props => { const cst = props.row.original; - const info = mapStatusInfo.get(cst.status); return (<>
-

Статус: {info!.tooltip}

+

Статус: {describeExpressionStatus(cst.status)}

); } }), - columnHelper.accessor(cst => getCstTypificationLabel(cst), { + columnHelper.accessor(cst => labelCstTypification(cst), { id: 'type', header: 'Типизация', size: 150, diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression.tsx index 29ae9ec2..0578585b 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression.tsx @@ -10,7 +10,8 @@ import useCheckExpression from '../../hooks/useCheckExpression'; import { IConstituenta } from '../../models/rsform'; import { IRSErrorDescription, SyntaxTree } from '../../models/rslang'; import { TokenID } from '../../models/rslang'; -import { getCstExpressionPrefix, getTypificationLabel } from '../../utils/staticUI'; +import { labelTypification } from '../../utils/labels'; +import { getCstExpressionPrefix } from '../../utils/misc'; import ParsingResult from './elements/ParsingResult'; import RSLocalButton from './elements/RSLocalButton'; import RSTokenButton from './elements/RSTokenButton'; @@ -67,7 +68,7 @@ function EditorRSExpression({ rsInput.current?.view?.focus(); } setIsModified(false); - setTypification(getTypificationLabel({ + setTypification(labelTypification({ isValid: parse.parseResult, resultType: parse.typification, args: parse.args @@ -111,49 +112,49 @@ function EditorRSExpression({
- - - - - - - - - + + + + + + + + +
- - - - - - - - - - - - - - + + + + + + + + + + + + + +
- - - - - - - - - - - - - - - + + + + + + + + + + + + + + +
diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph.tsx index b0a8975c..af19a619 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph.tsx @@ -21,9 +21,10 @@ import { prefixes, resources, TIMEOUT_GRAPH_REFRESH } from '../../utils/constant import { Graph } from '../../utils/Graph'; import { SelectorGraphLayout } from '../../utils/selectors'; import { SelectorGraphColoring } from '../../utils/selectors'; -import { getCstClassColor, getCstStatusBgColor, - mapColoringLabels, mapLayoutLabels -} from '../../utils/staticUI'; +import { colorbgCstClass } from '../../utils/color'; +import { colorbgCstStatus } from '../../utils/color'; +import { mapLabelColoring } from '../../utils/labels'; +import { mapLableLayout } from '../../utils/labels'; import DlgGraphOptions from './DlgGraphOptions'; import ConstituentaTooltip from './elements/ConstituentaTooltip'; @@ -32,10 +33,10 @@ const TREE_SIZE_MILESTONE = 50; function getCstNodeColor(cst: IConstituenta, coloringScheme: ColoringScheme, colors: IColorTheme): string { if (coloringScheme === 'type') { - return getCstClassColor(cst.cst_class, colors); + return colorbgCstClass(cst.cst_class, colors); } if (coloringScheme === 'status') { - return getCstStatusBgColor(cst.status, colors); + return colorbgCstStatus(cst.status, colors); } return ''; } @@ -407,7 +408,7 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra options={SelectorGraphColoring} isSearchable={false} placeholder='Выберите цвет' - value={coloringScheme ? { value: coloringScheme, label: mapColoringLabels.get(coloringScheme) } : null} + value={coloringScheme ? { value: coloringScheme, label: mapLabelColoring.get(coloringScheme) } : null} onChange={data => setColoringScheme(data?.value ?? SelectorGraphColoring[0].value)} /> @@ -417,7 +418,7 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra options={SelectorGraphLayout} isSearchable={false} placeholder='Способ расположения' - value={layout ? { value: layout, label: mapLayoutLabels.get(layout) } : null} + value={layout ? { value: layout, label: mapLableLayout.get(layout) } : null} onChange={data => handleChangeLayout(data?.value ?? SelectorGraphLayout[0].value)} />
diff --git a/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx b/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx index 0c086c45..0e7bffd3 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx @@ -17,7 +17,7 @@ import useModificationPrompt from '../../hooks/useModificationPrompt'; import { ICstCreateData, ICstRenameData } from '../../models/rsform'; import { SyntaxTree } from '../../models/rslang'; import { EXTEOR_TRS_FILE, prefixes, TIMEOUT_UI_REFRESH } from '../../utils/constants'; -import { createAliasFor } from '../../utils/staticUI'; +import { createAliasFor } from '../../utils/misc'; import DlgCloneRSForm from './DlgCloneRSForm'; import DlgCreateCst from './DlgCreateCst'; import DlgDeleteCst from './DlgDeleteCst'; diff --git a/rsconcept/frontend/src/pages/RSFormPage/elements/DependencyModePicker.tsx b/rsconcept/frontend/src/pages/RSFormPage/elements/DependencyModePicker.tsx index dac8b7d9..78aac3e7 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/elements/DependencyModePicker.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/elements/DependencyModePicker.tsx @@ -4,7 +4,7 @@ import Dropdown from '../../../components/Common/Dropdown'; import DropdownButton from '../../../components/Common/DropdownButton'; import useDropdown from '../../../hooks/useDropdown'; import { DependencyMode } from '../../../models/miscelanious'; -import { getDependencyLabel } from '../../../utils/staticUI'; +import { labelDependencyMode } from '../../../utils/labels'; interface DependencyModePickerProps { value: DependencyMode @@ -27,7 +27,7 @@ function DependencyModePicker({ value, onChange }: DependencyModePickerProps) { tabIndex={-1} onClick={pickerMenu.toggle} > - {getDependencyLabel(value)} + {labelDependencyMode(value)} { pickerMenu.isActive && diff --git a/rsconcept/frontend/src/pages/RSFormPage/elements/MatchModePicker.tsx b/rsconcept/frontend/src/pages/RSFormPage/elements/MatchModePicker.tsx index 5611a801..2e4338f2 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/elements/MatchModePicker.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/elements/MatchModePicker.tsx @@ -4,7 +4,7 @@ import Dropdown from '../../../components/Common/Dropdown'; import DropdownButton from '../../../components/Common/DropdownButton'; import useDropdown from '../../../hooks/useDropdown'; import { CstMatchMode } from '../../../models/miscelanious'; -import { getCstCompareLabel } from '../../../utils/staticUI'; +import { labelCstMathchMode } from '../../../utils/labels'; interface MatchModePickerProps { value: CstMatchMode @@ -27,7 +27,7 @@ function MatchModePicker({ value, onChange }: MatchModePickerProps) { tabIndex={-1} onClick={pickerMenu.toggle} > - {getCstCompareLabel(value)} + {labelCstMathchMode(value)} { pickerMenu.isActive && diff --git a/rsconcept/frontend/src/pages/RSFormPage/elements/ParsingResult.tsx b/rsconcept/frontend/src/pages/RSFormPage/elements/ParsingResult.tsx index ad5db969..d9d9d3ef 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/elements/ParsingResult.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/elements/ParsingResult.tsx @@ -1,5 +1,6 @@ import { IExpressionParse, IRSErrorDescription, SyntaxTree } from '../../../models/rslang'; -import { getRSErrorMessage, getRSErrorPrefix } from '../../../utils/staticUI'; +import { describeRSError } from '../../../utils/labels'; +import { getRSErrorPrefix } from '../../../utils/misc'; interface ParsingResultProps { data: IExpressionParse @@ -22,7 +23,7 @@ function ParsingResult({ data, onShowAST, onShowError }: ParsingResultProps) { return (

onShowError(error)}> {error.isCritical ? 'Ошибка' : 'Предупреждение'} {getRSErrorPrefix(error)}: - {getRSErrorMessage(error)} + {describeRSError(error)}

); })} diff --git a/rsconcept/frontend/src/pages/RSFormPage/elements/RSTokenButton.tsx b/rsconcept/frontend/src/pages/RSFormPage/elements/RSTokenButton.tsx index 2a9563cf..80665175 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/elements/RSTokenButton.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/elements/RSTokenButton.tsx @@ -1,25 +1,25 @@ import { TokenID } from '../../../models/rslang'; -import { getRSButtonData } from '../../../utils/staticUI' +import { describeToken, labelToken } from '../../../utils/labels'; interface RSTokenButtonProps { - id: TokenID + token: TokenID disabled?: boolean onInsert: (token: TokenID, key?: string) => void } -function RSTokenButton({ id, disabled, onInsert }: RSTokenButtonProps) { - const data = getRSButtonData(id); - const width = data.text.length > 3 ? 'w-[4rem]' : 'w-[2rem]'; +function RSTokenButton({ token, disabled, onInsert }: RSTokenButtonProps) { + const label = labelToken(token); + const width = label.length > 3 ? 'w-[4rem]' : 'w-[2rem]'; return ( ); } diff --git a/rsconcept/frontend/src/pages/RSFormPage/elements/StatusBar.tsx b/rsconcept/frontend/src/pages/RSFormPage/elements/StatusBar.tsx index 3c788569..7d5fdb33 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/elements/StatusBar.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/elements/StatusBar.tsx @@ -4,7 +4,8 @@ import { useConceptTheme } from '../../../context/ThemeContext'; import { ExpressionStatus } from '../../../models/rsform'; import { type IConstituenta, inferStatus } from '../../../models/rsform'; import { IExpressionParse, ParsingStatus } from '../../../models/rslang'; -import { getCstStatusBgColor, mapStatusInfo } from '../../../utils/staticUI'; +import { colorbgCstStatus } from '../../../utils/color'; +import { describeExpressionStatus, labelExpressionStatus } from '../../../utils/labels'; interface StatusBarProps { isModified?: boolean @@ -25,13 +26,12 @@ function StatusBar({ isModified, constituenta, parseData }: StatusBarProps) { return inferStatus(constituenta?.parse?.status, constituenta?.parse?.valueClass); }, [isModified, constituenta, parseData]); - const data = mapStatusInfo.get(status)!; return ( -
- Статус: [ {data.text} ] + Статус: [ {labelExpressionStatus(status)} ]
) } diff --git a/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx b/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx index d01c5874..26df0582 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx @@ -9,8 +9,10 @@ import { DependencyMode } from '../../../models/miscelanious'; import { CstMatchMode } from '../../../models/miscelanious'; import { applyGraphFilter } from '../../../models/miscelanious'; import { CstType, extractGlobals, IConstituenta, matchConstituenta } from '../../../models/rsform'; +import { createMockConstituenta } from '../../../models/rsform'; +import { colorfgCstStatus } from '../../../utils/color'; import { prefixes } from '../../../utils/constants'; -import { getCstDescription, getCstStatusFgColor, getMockConstituenta } from '../../../utils/staticUI'; +import { describeConstituenta } from '../../../utils/labels'; import ConstituentaTooltip from './ConstituentaTooltip'; import DependencyModePicker from './DependencyModePicker'; import MatchModePicker from './MatchModePicker'; @@ -74,7 +76,7 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }: if (diff.length > 0) { diff.forEach( (alias, index) => filtered.push( - getMockConstituenta( + createMockConstituenta( schema.id, -index, alias, @@ -124,8 +126,8 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }: className='min-w-[3.1rem] max-w-[3.1rem] px-1 text-center rounded-md whitespace-nowrap' style={{ borderWidth: '1px', - borderColor: getCstStatusFgColor(cst.status, colors), - color: getCstStatusFgColor(cst.status, colors), + borderColor: colorfgCstStatus(cst.status, colors), + color: colorfgCstStatus(cst.status, colors), fontWeight: 600, backgroundColor: isMockCst(cst) ? colors.bgWarning : colors.bgInput }} @@ -136,7 +138,7 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }: ); } }), - columnHelper.accessor(cst => getCstDescription(cst), { + columnHelper.accessor(cst => describeConstituenta(cst), { id: 'description', header: 'Описание', size: 500, diff --git a/rsconcept/frontend/src/utils/Graph.ts b/rsconcept/frontend/src/utils/Graph.ts index 32f66d94..b0ec1dfa 100644 --- a/rsconcept/frontend/src/utils/Graph.ts +++ b/rsconcept/frontend/src/utils/Graph.ts @@ -1,4 +1,6 @@ -// ======== ID based fast Graph implementation ============= +/** + * Represents single node of a {@link Graph}, as implemented by storing outgoing and incoming connections. + */ export class GraphNode { id: number; outputs: number[]; @@ -36,6 +38,11 @@ export class GraphNode { } } +/** + * Represents a Graph. + * + * This class is optimized for TermGraph use case and not supposed to be used as generic graph implementation. + */ export class Graph { nodes: Map = new Map(); diff --git a/rsconcept/frontend/src/utils/color.ts b/rsconcept/frontend/src/utils/color.ts index 4501db11..db386714 100644 --- a/rsconcept/frontend/src/utils/color.ts +++ b/rsconcept/frontend/src/utils/color.ts @@ -1,5 +1,8 @@ // =========== Modules contains all dynamic color definitions ========== +import { CstClass, ExpressionStatus } from '../models/rsform' +import { ISyntaxTreeNode, TokenID } from '../models/rslang' + // ============= MAIN COLOR THEMES ========== export interface IColorTheme { @@ -269,3 +272,115 @@ export const bracketsDarkT = { color: darkT.fgSelected }, }; + +// =========== Misc colors ====================== +export function colorbgSyntaxTree(node: ISyntaxTreeNode, colors: IColorTheme): string { + switch (node.typeID) { + case TokenID.PUNC_DEFINE: + case TokenID.PUNC_STRUCT: + case TokenID.ID_LOCAL: + return colors.bgGreen; + + case TokenID.ID_GLOBAL: + case TokenID.ID_FUNCTION: + case TokenID.ID_PREDICATE: + case TokenID.ID_RADICAL: + case TokenID.LIT_INTEGER: + case TokenID.LIT_EMPTYSET: + case TokenID.LIT_INTSET: + return colors.bgTeal; + + case TokenID.FORALL: + case TokenID.EXISTS: + case TokenID.NOT: + case TokenID.AND: + case TokenID.OR: + case TokenID.IMPLICATION: + case TokenID.EQUIVALENT: + case TokenID.GREATER: + case TokenID.LESSER: + case TokenID.EQUAL: + case TokenID.NOTEQUAL: + case TokenID.GREATER_OR_EQ: + case TokenID.LESSER_OR_EQ: + case TokenID.IN: + case TokenID.NOTIN: + case TokenID.SUBSET_OR_EQ: + case TokenID.SUBSET: + case TokenID.NOTSUBSET: + return colors.bgOrange; + + case TokenID.NT_TUPLE: + case TokenID.NT_ENUMERATION: + case TokenID.BIGPR: + case TokenID.SMALLPR: + case TokenID.FILTER: + case TokenID.PLUS: + case TokenID.MINUS: + case TokenID.MULTIPLY: + case TokenID.BOOLEAN: + case TokenID.DECART: + case TokenID.INTERSECTION: + case TokenID.UNION: + case TokenID.SET_MINUS: + case TokenID.SYMMINUS: + case TokenID.REDUCE: + case TokenID.CARD: + case TokenID.BOOL: + case TokenID.DEBOOL: + return colors.bgBlue; + + case TokenID.NT_FUNC_DEFINITION: + case TokenID.NT_DECLARATIVE_EXPR: + case TokenID.NT_IMPERATIVE_EXPR: + case TokenID.NT_RECURSIVE_FULL: + case TokenID.NT_ENUM_DECL: + case TokenID.NT_TUPLE_DECL: + case TokenID.NT_ARG_DECL: + case TokenID.NT_FUNC_CALL: + case TokenID.NT_ARGUMENTS: + case TokenID.NT_IMP_DECLARE: + case TokenID.NT_IMP_ASSIGN: + case TokenID.NT_IMP_LOGIC: + case TokenID.NT_RECURSIVE_SHORT: + return ''; + + case TokenID.PUNC_ASSIGN: + case TokenID.PUNC_ITERATE: + return colors.bgRed; + } + // node + return colors.bgRed; +} + +export function colorbgCstStatus(status: ExpressionStatus, colors: IColorTheme): string { + switch (status) { + case ExpressionStatus.VERIFIED: return colors.bgGreen; + case ExpressionStatus.INCORRECT: return colors.bgRed; + case ExpressionStatus.INCALCULABLE: return colors.bgOrange; + case ExpressionStatus.PROPERTY: return colors.bgTeal; + case ExpressionStatus.UNKNOWN: return colors.bgBlue; + case ExpressionStatus.UNDEFINED: return colors.bgBlue; + } +} + +export function colorfgCstStatus(status: ExpressionStatus, colors: IColorTheme): string { + switch (status) { + case ExpressionStatus.VERIFIED: return colors.fgGreen; + case ExpressionStatus.INCORRECT: return colors.fgRed; + case ExpressionStatus.INCALCULABLE: return colors.fgOrange; + case ExpressionStatus.PROPERTY: return colors.fgTeal; + case ExpressionStatus.UNKNOWN: return colors.fgBlue; + case ExpressionStatus.UNDEFINED: return colors.fgBlue; + } +} + +export function colorbgCstClass(cstClass: CstClass, colors: IColorTheme): string { + switch (cstClass) { + case CstClass.BASIC: return colors.bgGreen; + case CstClass.DERIVED: return colors.bgBlue; + case CstClass.STATEMENT: return colors.bgRed; + case CstClass.TEMPLATE: return colors.bgTeal; + } +} + diff --git a/rsconcept/frontend/src/utils/labels.ts b/rsconcept/frontend/src/utils/labels.ts new file mode 100644 index 00000000..902b660c --- /dev/null +++ b/rsconcept/frontend/src/utils/labels.ts @@ -0,0 +1,514 @@ +// =========== Modules contains all text descriptors ========== + +import { Grammeme,IGramData } from '../models/language'; +import { CstMatchMode, DependencyMode, HelpTopic } from '../models/miscelanious'; +import { CstClass, CstType, ExpressionStatus, IConstituenta } from '../models/rsform'; +import { IFunctionArg, IRSErrorDescription, ISyntaxTreeNode, ParsingStatus, RSErrorType, TokenID } from '../models/rslang'; + +export function describeConstituenta(cst: IConstituenta): string { + if (cst.cst_type === CstType.STRUCTURED) { + return ( + cst.term_resolved || cst.term_raw || + cst.definition_resolved || cst.definition_raw || + cst.convention || + cst.definition_formal + ); + } else { + return ( + cst.term_resolved || cst.term_raw || + cst.definition_resolved || cst.definition_raw || + cst.definition_formal || + cst.convention + ); + } +} + +export function labelConstituenta(cst: IConstituenta) { + return `${cst.alias}: ${describeConstituenta(cst)}`; +} + +export function labelToken(id: TokenID): string { + switch (id) { + case TokenID.BOOLEAN: return 'ℬ()'; + case TokenID.DECART: return '×'; + case TokenID.PUNC_PL: return '( )'; + case TokenID.PUNC_SL: return '[ ]'; + case TokenID.FORALL: return '∀'; + case TokenID.EXISTS: return '∃'; + case TokenID.NOT: return '¬'; + case TokenID.AND: return '&'; + case TokenID.OR: return '∨'; + case TokenID.IMPLICATION: return '⇒'; + case TokenID.EQUIVALENT: return '⇔'; + case TokenID.LIT_EMPTYSET: return '∅'; + case TokenID.LIT_INTSET: return 'Z'; + case TokenID.EQUAL: return '='; + case TokenID.NOTEQUAL: return '≠'; + case TokenID.GREATER_OR_EQ: return '≥'; + case TokenID.LESSER_OR_EQ: return '≤'; + case TokenID.IN: return '∈'; + case TokenID.NOTIN: return '∉'; + case TokenID.SUBSET_OR_EQ: return '⊆'; + case TokenID.SUBSET: return '⊂'; + case TokenID.NOTSUBSET: return '⊄'; + case TokenID.INTERSECTION: return '∩'; + case TokenID.UNION: return '∪'; + case TokenID.SET_MINUS: return '\\'; + case TokenID.SYMMINUS: return '∆'; + case TokenID.NT_DECLARATIVE_EXPR: return 'D{}'; + case TokenID.NT_IMPERATIVE_EXPR: return 'I{}'; + case TokenID.NT_RECURSIVE_FULL: return 'R{}'; + case TokenID.BIGPR: return 'Pr1()'; + case TokenID.SMALLPR: return 'pr1()'; + case TokenID.FILTER: return 'Fi1[]()'; + case TokenID.REDUCE: return 'red()'; + case TokenID.CARD: return 'card()'; + case TokenID.BOOL: return 'bool()'; + case TokenID.DEBOOL: return 'debool()'; + case TokenID.PUNC_ASSIGN: return ':='; + case TokenID.PUNC_ITERATE: return ':∈'; + } + return `no label: ${id}`; +} + +export function describeToken(id: TokenID): string { + switch (id) { + case TokenID.BOOLEAN: return 'Булеан [Alt + E]'; + case TokenID.DECART: return 'Декартово произведение [Shift + 8 / Alt + Shift + E]'; + case TokenID.PUNC_PL: return 'Скобки вокруг выражения [Alt + Shift + 9 ]'; + case TokenID.PUNC_SL: return 'Скобки вокруг выражения [Alt + [ ]'; + case TokenID.FORALL: return 'Квантор всеобщности [`]'; + case TokenID.EXISTS: return 'Квантор существования [Shift + `]'; + case TokenID.NOT: return 'Отрицание [Alt + `]'; + case TokenID.AND: return 'Конъюнкция [Alt + 3 ~ Shift + 7]'; + case TokenID.OR: return 'Дизъюнкция [Alt + Shift + 3]'; + case TokenID.IMPLICATION: return 'Импликация [Alt + 4]'; + case TokenID.EQUIVALENT: return 'Эквивалентность [Alt + Shift + 4]'; + case TokenID.LIT_EMPTYSET: return 'Пустое множество [Alt + X]'; + case TokenID.LIT_INTSET: return 'Целые числа [Alt + Z]'; + case TokenID.EQUAL: return 'Равенство'; + case TokenID.NOTEQUAL: return 'Неравенство [Alt + Shift + `]'; + case TokenID.GREATER_OR_EQ: return 'Больше или равно [Alt + Shift + 7]'; + case TokenID.LESSER_OR_EQ: return 'Меньше или равно [Alt + Shift + 8]'; + case TokenID.IN: return 'Быть элементом (принадлежит) [Alt + 1]'; + case TokenID.NOTIN: return 'Не принадлежит [Alt + Shift + 1]'; + case TokenID.SUBSET_OR_EQ: return 'Быть частью (нестрогое подмножество) [Alt + 2]'; + case TokenID.SUBSET: return 'Строгое подмножество [Alt + 7]'; + case TokenID.NOTSUBSET: return 'Не подмножество [Alt + Shift + 2]'; + case TokenID.INTERSECTION: return 'Пересечение [Alt + A]'; + case TokenID.UNION: return 'Объединение [Alt + S]'; + case TokenID.SET_MINUS: return 'Разность множеств [Alt + 5]'; + case TokenID.SYMMINUS: return 'Симметрическая разность [Alt + Shift + 5]'; + case TokenID.NT_DECLARATIVE_EXPR: return 'Декларативная форма определения терма [Alt + D]'; + case TokenID.NT_IMPERATIVE_EXPR: return 'Императивная форма определения терма [Alt + G]'; + case TokenID.NT_RECURSIVE_FULL: return 'Рекурсивная (цикличная) форма определения терма [Alt + T]'; + case TokenID.BIGPR: return 'Большая проекция [Alt + Q]'; + case TokenID.SMALLPR: return 'Малая проекция [Alt + W]'; + case TokenID.FILTER: return 'Фильтр [Alt + F]'; + case TokenID.REDUCE: return 'Множество-сумма [Alt + R]'; + case TokenID.CARD: return 'Мощность [Alt + C]'; + case TokenID.BOOL: return 'Синглетон [Alt + B]'; + case TokenID.DEBOOL: return 'Десинглетон [Alt + V]'; + case TokenID.PUNC_ASSIGN: return 'Присвоение (императивный синтаксис) [Alt + Shift + 6]'; + case TokenID.PUNC_ITERATE: return 'Перебор элементов множества (императивный синтаксис) [Alt + 6]'; + } + return `no description: ${id}`; +} + +export function labelCstMathchMode(mode: CstMatchMode): string { + switch (mode) { + case CstMatchMode.ALL: return 'везде'; + case CstMatchMode.EXPR: return 'выраж'; + case CstMatchMode.TERM: return 'термин'; + case CstMatchMode.TEXT: return 'текст'; + case CstMatchMode.NAME: return 'имя'; + } +} + +export function labelDependencyMode(mode: DependencyMode): string { + switch (mode) { + case DependencyMode.ALL: return 'вся схема'; + case DependencyMode.EXPRESSION: return 'выражение'; + case DependencyMode.OUTPUTS: return 'потребители'; + case DependencyMode.INPUTS: return 'поставщики'; + case DependencyMode.EXPAND_INPUTS: return 'влияющие'; + case DependencyMode.EXPAND_OUTPUTS: return 'зависимые'; + } +} + +export const mapLableLayout: Map = +new Map([ + ['forceatlas2', 'Граф: Атлас 2D'], + ['forceDirected2d', 'Граф: Силы 2D'], + ['forceDirected3d', 'Граф: Силы 3D'], + ['treeTd2d', 'Граф: ДеревоВерт 2D'], + ['treeTd3d', 'Граф: ДеревоВерт 3D'], + ['treeLr2d', 'Граф: ДеревоГор 2D'], + ['treeLr3d', 'Граф: ДеревоГор 3D'], + ['radialOut2d', 'Граф: Радиальная 2D'], + ['radialOut3d', 'Граф: Радиальная 3D'], + ['circular2d', 'Граф: Круговая'], + ['hierarchicalTd', 'Граф: ИерархияВерт'], + ['hierarchicalLr', 'Граф: ИерархияГор'], + ['nooverlap', 'Граф: Без перекрытия'] +]); + +export const mapLabelColoring: Map = +new Map([ + ['none', 'Цвет: моно'], + ['status', 'Цвет: статус'], + ['type', 'Цвет: класс'], +]); + +export function labelExpressionStatus(status: ExpressionStatus): string { + switch (status) { + case ExpressionStatus.VERIFIED: return 'ок'; + case ExpressionStatus.INCORRECT: return 'ошибка'; + case ExpressionStatus.INCALCULABLE: return 'невыч'; + case ExpressionStatus.PROPERTY: return 'св-во'; + case ExpressionStatus.UNKNOWN: return 'неизв'; + case ExpressionStatus.UNDEFINED: return 'N/A'; + } +} + +export function describeExpressionStatus(status: ExpressionStatus): string { + switch (status) { + case ExpressionStatus.VERIFIED: return 'выражение корректно и вычислимо'; + case ExpressionStatus.INCORRECT: return 'ошибка в выражении'; + case ExpressionStatus.INCALCULABLE: return 'выражение не вычислимо'; + case ExpressionStatus.PROPERTY: return 'можно проверить принадлежность, но нельзя получить значение'; + case ExpressionStatus.UNKNOWN: return 'требует проверки выражения'; + case ExpressionStatus.UNDEFINED: return 'произошла ошибка при проверке выражения'; + } +} + +export function labelHelpTopic(topic: HelpTopic): string { + switch (topic) { + case HelpTopic.MAIN: return 'Портал'; + case HelpTopic.RSLANG: return 'Экспликация'; + case HelpTopic.LIBRARY: return 'Библиотека'; + case HelpTopic.RSFORM: return '- паспорт схемы'; + case HelpTopic.CSTLIST: return '- список конституент'; + case HelpTopic.CONSTITUENTA: return '- конституента'; + case HelpTopic.GRAPH_TERM: return '- граф термов'; + case HelpTopic.EXTEOR: return 'Экстеор'; + case HelpTopic.API: return 'REST API'; + } +} + +export function describeHelpTopic(topic: HelpTopic): string { + switch (topic) { + case HelpTopic.MAIN: return 'Общая справка по порталу'; + case HelpTopic.RSLANG: return 'Справка по языку родов структур и экспликации'; + case HelpTopic.LIBRARY: return 'Описание работы с библиотекой схем'; + case HelpTopic.RSFORM: return 'Описание работы с описанием схемы'; + case HelpTopic.CSTLIST: return 'Описание работы со списком конституентт'; + case HelpTopic.CONSTITUENTA: return 'Описание редактирования конституенты'; + case HelpTopic.GRAPH_TERM: return 'Описание работы с графом термов схемы'; + case HelpTopic.EXTEOR: return 'Справка по программе для экспликации "Экстеор" для Windows'; + case HelpTopic.API: return 'Описание интерфейса для разработчиков'; + } +} + +export function labelCstType(type: CstType) { + switch (type) { + case CstType.BASE: return 'Базисное множество'; + case CstType.CONSTANT: return 'Константное множество'; + case CstType.STRUCTURED: return 'Родовая структура'; + case CstType.AXIOM: return 'Аксиома'; + case CstType.TERM: return 'Терм'; + case CstType.FUNCTION: return 'Терм-функция'; + case CstType.PREDICATE: return 'Предикат-функция'; + case CstType.THEOREM: return 'Теорема'; + } +} + +export function labelCstClass(cclass: CstClass): string { + switch (cclass) { + case CstClass.BASIC: return 'базовый'; + case CstClass.DERIVED: return 'производный'; + case CstClass.STATEMENT: return 'утверждение'; + case CstClass.TEMPLATE: return 'шаблон'; + } +} + +export function describeCstClass(cclass: CstClass): string { + switch (cclass) { + case CstClass.BASIC: return 'неопределяемое понятие, требует конвенции'; + case CstClass.DERIVED: return 'выводимое понятие, задаваемое определением'; + case CstClass.STATEMENT: return 'утверждение формальной логики'; + case CstClass.TEMPLATE: return 'параметризованный шаблон определения'; + } +} + +export function labelTypification({ isValid, resultType, args }: { + isValid: boolean; + resultType: string; + args: IFunctionArg[]; +}): string { + if (!isValid) { + return 'N/A'; + } + if (resultType === '' || resultType === 'LOGIC') { + resultType = 'Logical'; + } + if (args.length === 0) { + return resultType; + } + const argsText = args.map(arg => arg.typification).join(', '); + return `${resultType} 🠔 [${argsText}]`; +} + +export function labelCstTypification(cst: IConstituenta): string { + return labelTypification({ + isValid: cst.parse.status === ParsingStatus.VERIFIED, + resultType: cst.parse.typification, + args: cst.parse.args + }); +} + +export function labelSyntaxTree(node: ISyntaxTreeNode): string { + switch (node.typeID) { + case TokenID.ID_LOCAL: + case TokenID.ID_GLOBAL: + case TokenID.ID_FUNCTION: + case TokenID.ID_PREDICATE: + case TokenID.ID_RADICAL: + return node.data.value as string; + + case TokenID.LIT_INTEGER: return String(node.data.value as number); + + case TokenID.BIGPR: return 'Pr' + (node.data.value as string[]).toString(); + case TokenID.SMALLPR: return 'pr' + (node.data.value as string[]).toString(); + case TokenID.FILTER: return 'Fi' + (node.data.value as string[]).toString(); + + case TokenID.PLUS: return '+'; + case TokenID.MINUS: return '-'; + case TokenID.MULTIPLY: return '*'; + case TokenID.GREATER: return '>'; + case TokenID.LESSER: return '<'; + + case TokenID.NT_TUPLE: return 'TUPLE'; + case TokenID.NT_ENUMERATION: return 'ENUM'; + + case TokenID.NT_ENUM_DECL: return 'ENUM_DECLARATION'; + case TokenID.NT_TUPLE_DECL: return 'TUPLE_DECLARATION'; + case TokenID.PUNC_DEFINE: return 'DEFINITION'; + case TokenID.PUNC_STRUCT: return 'STRUCTURE_DEFITION'; + + case TokenID.NT_ARG_DECL: return 'ARG'; + case TokenID.NT_FUNC_CALL: return 'CALL'; + case TokenID.NT_ARGUMENTS: return 'ARGS'; + + case TokenID.NT_FUNC_DEFINITION: return 'FUNCTION_DEFINITION'; + case TokenID.NT_IMP_DECLARE: return 'IDECLARE'; + case TokenID.NT_IMP_ASSIGN: return 'IASSIGN'; + case TokenID.NT_IMP_LOGIC: return 'ICHECK'; + + case TokenID.NT_RECURSIVE_SHORT: return labelToken(TokenID.NT_RECURSIVE_FULL); + + case TokenID.BOOLEAN: + case TokenID.DECART: + case TokenID.FORALL: + case TokenID.EXISTS: + case TokenID.NOT: + case TokenID.AND: + case TokenID.OR: + case TokenID.IMPLICATION: + case TokenID.EQUIVALENT: + case TokenID.LIT_EMPTYSET: + case TokenID.LIT_INTSET: + case TokenID.EQUAL: + case TokenID.NOTEQUAL: + case TokenID.GREATER_OR_EQ: + case TokenID.LESSER_OR_EQ: + case TokenID.IN: + case TokenID.NOTIN: + case TokenID.SUBSET_OR_EQ: + case TokenID.SUBSET: + case TokenID.NOTSUBSET: + case TokenID.INTERSECTION: + case TokenID.UNION: + case TokenID.SET_MINUS: + case TokenID.SYMMINUS: + case TokenID.NT_DECLARATIVE_EXPR: + case TokenID.NT_IMPERATIVE_EXPR: + case TokenID.NT_RECURSIVE_FULL: + case TokenID.REDUCE: + case TokenID.CARD: + case TokenID.BOOL: + case TokenID.DEBOOL: + case TokenID.PUNC_ASSIGN: + case TokenID.PUNC_ITERATE: + return labelToken(node.typeID); + } + // node + return 'UNKNOWN ' + String(node.typeID); +} + +export function labelGrammeme(gram: IGramData): string { + switch (gram.type) { + case Grammeme.NOUN: return 'ЧР: сущ'; + case Grammeme.VERB: return 'ЧР: глагол'; + case Grammeme.INFN: return 'ЧР: глагол инф'; + case Grammeme.ADJF: return 'ЧР: прил'; + case Grammeme.PRTF: return 'ЧР: прич'; + case Grammeme.ADJS: return 'ЧР: кр прил'; + case Grammeme.PRTS: return 'ЧР: кр прич'; + case Grammeme.COMP: return 'ЧР: компаратив'; + case Grammeme.GRND: return 'ЧР: деепричастие'; + case Grammeme.NUMR: return 'ЧР: число'; + case Grammeme.ADVB: return 'ЧР: наречие'; + case Grammeme.NPRO: return 'ЧР: местоимение'; + case Grammeme.PRED: return 'ЧР: предикатив'; + case Grammeme.PREP: return 'ЧР: предлог'; + case Grammeme.CONJ: return 'ЧР: союз'; + case Grammeme.PRCL: return 'ЧР: частица'; + case Grammeme.INTJ: return 'ЧР: междометие'; + case Grammeme.Abbr: return 'ЧР: аббревиатура'; + + case Grammeme.sing: return 'Число: един'; + case Grammeme.plur: return 'Число: множ'; + + case Grammeme.nomn: return 'Падеж: имен'; + case Grammeme.gent: return 'Падеж: род'; + case Grammeme.datv: return 'Падеж: дат'; + case Grammeme.accs: return 'Падеж: вин'; + case Grammeme.ablt: return 'Падеж: твор'; + case Grammeme.loct: return 'Падеж: пред'; + + case Grammeme.masc: return 'Род: муж'; + case Grammeme.femn: return 'Род: жен'; + case Grammeme.neut: return 'Род: ср'; + + case Grammeme.perf: return 'Совершенный: да'; + case Grammeme.impf: return 'Совершенный: нет'; + + case Grammeme.tran: return 'Переходный: да'; + case Grammeme.intr: return 'Переходный: нет'; + + case Grammeme.pres: return 'Время: наст'; + case Grammeme.past: return 'Время: прош'; + case Grammeme.futr: return 'Время: буд'; + + case Grammeme.per1: return 'Лицо: 1'; + case Grammeme.per2: return 'Лицо: 2'; + case Grammeme.per3: return 'Лицо: 3'; + + case Grammeme.impr: return 'Повелительный: да'; + case Grammeme.indc: return 'Повелительный: нет'; + + case Grammeme.incl: return 'Включающий: да'; + case Grammeme.excl: return 'Включающий: нет'; + + case Grammeme.pssv: return 'Страдательный: да'; + case Grammeme.actv: return 'Страдательный: нет'; + + case Grammeme.anim: return 'Одушевленный: да'; + case Grammeme.inan: return 'Одушевленный: нет'; + + case Grammeme.Infr: return 'Стиль: неформальный'; + case Grammeme.Slng: return 'Стиль: жаргон'; + case Grammeme.Arch: return 'Стиль: устаревший'; + case Grammeme.Litr: return 'Стиль: литературный'; + + case Grammeme.UNKN: return `Неизв: ${gram.data}`; + } +} + +export function describeRSError(error: IRSErrorDescription): string { + switch (error.errorType) { + case RSErrorType.syntax: + return 'Неопределенная синтаксическая ошибка'; + case RSErrorType.missingParanthesis: + return 'Некорректная конструкция языка родов структур, проверьте структуру выражения'; + case RSErrorType.missingCurlyBrace: + return "Пропущен символ '}'"; + case RSErrorType.invalidQuantifier: + return 'Некорректная кванторная декларация'; + case RSErrorType.expectedArgDeclaration: + return 'Ожидалось объявление аргументов терм-функции'; + case RSErrorType.expectedLocal: + return 'Ожидалось имя локальной переменной'; + + case RSErrorType.localDoubleDeclare: + return `Предупреждение! Повторное объявление локальной переменной ${error.params[0]}`; + case RSErrorType.localNotUsed: + return `Предупреждение! Переменная объявлена, но не использована: ${error.params[0]}`; + case RSErrorType.localUndeclared: + return `Использование необъявленной переменной: ${error.params[0]}`; + case RSErrorType.localShadowing: + return `Повторное объявление переменной: ${error.params[0]}`; + + case RSErrorType.typesNotEqual: + return `Типизация операндов не совпадает! ${error.params[0]} != ${error.params[1]}`; + case RSErrorType.globalNotTyped: + return `Типизация конституенты не определена: ${error.params[0]}`; + case RSErrorType.invalidDecart: + return `τ(α×b) = ℬ(𝔇τ(α)×𝔇τ(b)). Некорректная типизация аргумента: ${error.params[0]}`; + case RSErrorType.invalidBoolean: + return `τ(ℬ(a)) = ℬℬ𝔇τ(a). Некорректная типизация аргумента: ${error.params[0]}`; + case RSErrorType.invalidTypeOperation: + return `Типизация операнда теоретико-множественной операции не корректна: ${error.params[0]}`; + case RSErrorType.invalidCard: + return `Некорректная типизация аргумента операции мощности: ${error.params[0]}`; + case RSErrorType.invalidDebool: + return `τ(debool(a)) = 𝔇τ(a). Некорректная типизация аргумента: ${error.params[0]}`; + case RSErrorType.globalFuncMissing: + return `Неизвестное имя функции: ${error.params[0]}`; + case RSErrorType.globalFuncWithoutArgs: + return `Некорректное использование имени функции без аргументов: ${error.params[0]}`; + case RSErrorType.invalidReduce: + return `τ(red(a)) = ℬ𝔇𝔇τ(a). Некорректная типизация аргумента: ${error.params[0]}`; + case RSErrorType.invalidProjectionTuple: + return `Проекция не определена: ${error.params[0]} -> ${error.params[1]}`; + case RSErrorType.invalidProjectionSet: + return `τ(Pri(a)) = ℬ𝒞i𝔇τ(a). Некорректная типизация аргумента: ${error.params[0]}`; + case RSErrorType.invalidEnumeration: + return `Типизация аргументов перечисления не совпадает: ${error.params[0]} != ${error.params[1]}`; + case RSErrorType.ivalidBinding: + return `Количество переменных в кортеже не соответствует размерности декартова произведения`; + case RSErrorType.localOutOfScope: + return `Использование имени переменной вне области действия: ${error.params[0]}`; + case RSErrorType.invalidElementPredicat: + return `Несоответствие типизаций операндов для оператора: ${error.params[0]}${error.params[1]}${error.params[2]}`; + case RSErrorType.invalidArgsArtity: + return `Неверное число аргументов терм-функции: ${error.params[0]} != ${error.params[1]}`; + case RSErrorType.invalidArgumentType: + return `Типизация аргумента терм-функции не соответствует объявленной: ${error.params[0]} != ${error.params[1]}`; + case RSErrorType.invalidEqualsEmpty: + return `Только множества можно сравнивать с пустым множеством: ${error.params[0]}`; + case RSErrorType.globalStructure: + return `Выражение родовой структуры должно быть ступенью`; + case RSErrorType.globalExpectedFunction: + return `Ожидалось выражение объявления функции`; + case RSErrorType.emptySetUsage: + return `Запрещено использование пустого множества как типизированного выражения`; + case RSErrorType.radicalUsage: + return `Радикалы запрещены вне деклараций терм-функции: ${error.params[0]}`; + case RSErrorType.invalidFilterArgumentType: + return `Типизация аргумента фильтра не корректна: ${error.params[0]}(${error.params[1]})`; + case RSErrorType.invalidFilterArity: + return `Количество параметров фильтра не соответствует количеству индексов`; + case RSErrorType.arithmeticNotSupported: + return `Тип не поддерживает арифметические операторы: ${error.params[0]}`; + case RSErrorType.typesNotCompatible: + return `Типы не совместимы для выбранной операции: ${error.params[0]} и ${error.params[1]}`; + case RSErrorType.orderingNotSupported: + return `Тип не поддерживает предикаты порядка: ${error.params[0]}`; + case RSErrorType.globalNoValue: + return `Используется неинтерпретируемый глобальный идентификатор: ${error.params[0]}`; + case RSErrorType.invalidPropertyUsage: + return `Использование неитерируемого множества в качестве значения`; + case RSErrorType.globalMissingAST: + return `Не удалось получить дерево разбора для глобального идентификатора: ${error.params[0]}`; + case RSErrorType.globalFuncNoInterpretation: + return `Функция не интерпретируется для данных аргументов`; + case RSErrorType.globalNonemptyBase: + return `Непустое выражение базисного/константного множества`; + case RSErrorType.globalUnexpectedType: + return `Типизация выражения не соответствует типу конституенты`; + } + return 'UNKNOWN ERROR'; +} + diff --git a/rsconcept/frontend/src/utils/misc.ts b/rsconcept/frontend/src/utils/misc.ts new file mode 100644 index 00000000..1e900091 --- /dev/null +++ b/rsconcept/frontend/src/utils/misc.ts @@ -0,0 +1,72 @@ + +// 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 { labelCstType } from './labels'; + +export function getCstTypePrefix(type: CstType) { + switch (type) { + case CstType.BASE: return 'X'; + case CstType.CONSTANT: return 'C'; + case CstType.STRUCTURED: return 'S'; + case CstType.AXIOM: return 'A'; + case CstType.TERM: return 'D'; + case CstType.FUNCTION: return 'F'; + case CstType.PREDICATE: return 'P'; + case CstType.THEOREM: return 'T'; + } +} + +export function getCstExpressionPrefix(cst: IConstituenta): string { + return cst.alias + (cst.cst_type === CstType.STRUCTURED ? '::=' : ':=='); +} + +export function getCstTypeShortcut(type: CstType) { + const prefix = labelCstType(type) + ' [Alt + '; + switch (type) { + case CstType.BASE: return prefix + '1]'; + case CstType.STRUCTURED: return prefix + '2]'; + case CstType.TERM: return prefix + '3]'; + case CstType.AXIOM: return prefix + '4]'; + case CstType.FUNCTION: return prefix + 'Q]'; + case CstType.PREDICATE: return prefix + 'W]'; + case CstType.CONSTANT: return prefix + '5]'; + case CstType.THEOREM: return prefix + '6]'; + } +} + +export function createAliasFor(type: CstType, schema: IRSForm): string { + const prefix = getCstTypePrefix(type); + if (!schema.items || schema.items.length <= 0) { + return `${prefix}1`; + } + const index = schema.items.reduce((prev, cst, index) => { + if (cst.cst_type !== type) { + return prev; + } + index = Number(cst.alias.slice(1 - cst.alias.length)) + 1; + return Math.max(prev, index); + }, 1); + return `${prefix}${index}`; +} + +export function cloneTitle(schema: IRSForm): string { + if (!schema.title.includes('[клон]')) { + return schema.title + ' [клон]'; + } else { + return (schema.title + '+'); + } +} + +export function getRSErrorPrefix(error: IRSErrorDescription): string { + const id = error.errorType.toString(16) + switch(resolveErrorClass(error.errorType)) { + case RSErrorClass.LEXER: return 'L' + id; + case RSErrorClass.PARSER: return 'P' + id; + case RSErrorClass.SEMANTIC: return 'S' + id; + case RSErrorClass.UNKNOWN: return 'U' + id; + } +} + diff --git a/rsconcept/frontend/src/utils/selectors.ts b/rsconcept/frontend/src/utils/selectors.ts index 87f9232d..67381b53 100644 --- a/rsconcept/frontend/src/utils/selectors.ts +++ b/rsconcept/frontend/src/utils/selectors.ts @@ -1,10 +1,11 @@ // Module: Selector maps import { LayoutTypes } from 'reagraph'; -import { Grammeme } from '../models/language'; +import { Grammeme, IGramData } from '../models/language'; import { CstType } from '../models/rsform'; import { ColoringScheme } from '../pages/RSFormPage/EditorTermGraph'; -import { getCstTypeLabel } from './staticUI'; +import { labelGrammeme } from './labels'; +import { labelCstType } from './labels'; export const SelectorGraphLayout: { value: LayoutTypes, label: string }[] = [ @@ -31,55 +32,37 @@ export const SelectorGraphColoring: { value: ColoringScheme, label: string }[] = export const SelectorCstType = ( Object.values(CstType)).map( - typeStr => ({ - value: typeStr as CstType, - label: getCstTypeLabel(typeStr as CstType) - }) - ); + typeStr => ({ + value: typeStr as CstType, + label: labelCstType(typeStr as CstType) + }) +); -export const SelectorGrammems: { value: Grammeme, label: string }[] = [ - { value: Grammeme.sing, label: 'Число: един' }, - { value: Grammeme.plur, label: 'Число: множ' }, +export interface IGrammemeOption { + value: Grammeme + label: string +} - { value: Grammeme.nomn, label: 'Падеж: имен' }, - { value: Grammeme.gent, label: 'Падеж: род' }, - { value: Grammeme.datv, label: 'Падеж: дат' }, - { value: Grammeme.accs, label: 'Падеж: вин' }, - { value: Grammeme.ablt, label: 'Падеж: твор' }, - { value: Grammeme.loct, label: 'Падеж: пред' }, +export const SelectorGrammems: IGrammemeOption[] = +[ + Grammeme.NOUN, Grammeme.VERB, - { value: Grammeme.NOUN, label: 'ЧР: сущ' }, - { value: Grammeme.VERB, label: 'ЧР: глагол' }, - { value: Grammeme.INFN, label: 'ЧР: глагол инф' }, - { value: Grammeme.ADJF, label: 'ЧР: прил' }, - { value: Grammeme.ADJS, label: 'ЧР: кр прил' }, - { value: Grammeme.PRTF, label: 'ЧР: прич' }, - { value: Grammeme.PRTS, label: 'ЧР: кр прич' }, + Grammeme.sing, Grammeme.plur, + Grammeme.nomn, Grammeme.gent, Grammeme.datv, + Grammeme.accs, Grammeme.ablt, Grammeme.loct, - { value: Grammeme.perf, label: 'Совершенный: да' }, - { value: Grammeme.impf, label: 'Совершенный: нет' }, + Grammeme.INFN, Grammeme.ADJF, Grammeme.PRTF, + Grammeme.ADJS, Grammeme.PRTS, - { value: Grammeme.tran, label: 'Переходный: да' }, - { value: Grammeme.intr, label: 'Переходный: нет' }, - - { value: Grammeme.pres, label: 'Время: наст' }, - { value: Grammeme.past, label: 'Время: прош' }, - { value: Grammeme.futr, label: 'Время: буд' }, - - { value: Grammeme.per1, label: 'Лицо: 1' }, - { value: Grammeme.per2, label: 'Лицо: 2' }, - { value: Grammeme.per3, label: 'Лицо: 3' }, - - { value: Grammeme.impr, label: 'Повелительный: да' }, - { value: Grammeme.indc, label: 'Повелительный: нет' }, - - { value: Grammeme.incl, label: 'Включающий: да' }, - { value: Grammeme.excl, label: 'Включающий: нет' }, - - { value: Grammeme.pssv, label: 'Страдательный: да' }, - { value: Grammeme.actv, label: 'Страдательный: нет' }, -]; - -// { value: Grammeme.masc, label: 'Род: муж' }, -// { value: Grammeme.femn, label: 'Род: жен' }, -// { value: Grammeme.neut, label: 'Род: ср' }, \ No newline at end of file + Grammeme.perf, Grammeme.impf, + Grammeme.tran, Grammeme.intr, + Grammeme.pres, Grammeme.past, Grammeme.futr, + Grammeme.per1, Grammeme.per2, Grammeme.per3, + Grammeme.impr, Grammeme.indc, + Grammeme.incl, Grammeme.excl, + Grammeme.pssv, Grammeme.actv, +].map( +gram => ({ + value: gram, + label: labelGrammeme({type: gram, data: ''} as IGramData) +})); diff --git a/rsconcept/frontend/src/utils/staticUI.ts b/rsconcept/frontend/src/utils/staticUI.ts deleted file mode 100644 index 9b807067..00000000 --- a/rsconcept/frontend/src/utils/staticUI.ts +++ /dev/null @@ -1,740 +0,0 @@ - -import { DependencyMode } from '../models/miscelanious'; -import { HelpTopic } from '../models/miscelanious'; -import { CstMatchMode } from '../models/miscelanious'; -import { ExpressionStatus } from '../models/rsform'; -import { CstClass, CstType, IConstituenta, IRSForm } from '../models/rsform'; -import { IFunctionArg, IRSErrorDescription, ISyntaxTreeNode, ParsingStatus, ValueClass } from '../models/rslang'; -import { resolveErrorClass, RSErrorClass, RSErrorType, TokenID } from '../models/rslang'; -import { IColorTheme } from './color'; - -export interface IDescriptor { - text: string - tooltip: string -} - -export function getCstDescription(cst: IConstituenta): string { - if (cst.cst_type === CstType.STRUCTURED) { - return ( - cst.term_resolved || cst.term_raw || - cst.definition_resolved || cst.definition_raw || - cst.convention || - cst.definition_formal - ); - } else { - return ( - cst.term_resolved || cst.term_raw || - cst.definition_resolved || cst.definition_raw || - cst.definition_formal || - cst.convention - ); - } -} - -export function getCstLabel(cst: IConstituenta) { - return `${cst.alias}: ${getCstDescription(cst)}`; -} - -export function getCstTypePrefix(type: CstType) { - switch (type) { - case CstType.BASE: return 'X'; - case CstType.CONSTANT: return 'C'; - case CstType.STRUCTURED: return 'S'; - case CstType.AXIOM: return 'A'; - case CstType.TERM: return 'D'; - case CstType.FUNCTION: return 'F'; - case CstType.PREDICATE: return 'P'; - case CstType.THEOREM: return 'T'; - } -} - -export function getCstExpressionPrefix(cst: IConstituenta): string { - return cst.alias + (cst.cst_type === CstType.STRUCTURED ? '::=' : ':=='); -} - -export function getRSButtonData(id: TokenID): IDescriptor { - switch (id) { - case TokenID.BOOLEAN: return { - text: 'ℬ()', - tooltip: 'Булеан [Alt + E]' - }; - case TokenID.DECART: return { - text: '×', - tooltip: 'Декартово произведение [Shift + 8 / Alt + Shift + E]' - }; - case TokenID.PUNC_PL: return { - text: '( )', - tooltip: 'Скобки вокруг выражения [Alt + Shift + 9 ]' - }; - case TokenID.PUNC_SL: return { - text: '[ ]', - tooltip: 'Скобки вокруг выражения [Alt + [ ]' - }; - case TokenID.FORALL: return { - text: '∀', - tooltip: 'Квантор всеобщности [`]' - }; - case TokenID.EXISTS: return { - text: '∃', - tooltip: 'Квантор существования [Shift + `]' - }; - case TokenID.NOT: return { - text: '¬', - tooltip: 'Отрицание [Alt + `]' - }; - case TokenID.AND: return { - text: '&', - tooltip: 'Конъюнкция [Alt + 3 ~ Shift + 7]' - }; - case TokenID.OR: return { - text: '∨', - tooltip: 'дизъюнкция [Alt + Shift + 3]' - }; - case TokenID.IMPLICATION: return { - text: '⇒', - tooltip: 'импликация [Alt + 4]' - }; - case TokenID.EQUIVALENT: return { - text: '⇔', - tooltip: 'эквивалентность [Alt + Shift + 4]' - }; - case TokenID.LIT_EMPTYSET: return { - text: '∅', - tooltip: 'пустое множество [Alt + X]' - }; - case TokenID.LIT_INTSET: return { - text: 'Z', - tooltip: 'целые числа [Alt + Z]' - }; - case TokenID.EQUAL: return { - text: '=', - tooltip: 'равенство' - }; - case TokenID.NOTEQUAL: return { - text: '≠', - tooltip: 'неравенство [Alt + Shift + `]' - }; - case TokenID.GREATER_OR_EQ: return { - text: '≥', - tooltip: 'больше или равно [Alt + Shift + 7]' - }; - case TokenID.LESSER_OR_EQ: return { - text: '≤', - tooltip: 'меньше или равно [Alt + Shift + 8]' - }; - case TokenID.IN: return { - text: '∈', - tooltip: 'быть элементом (принадлежит) [Alt + 1]' - }; - case TokenID.NOTIN: return { - text: '∉', - tooltip: 'не принадлежит [Alt + Shift + 1]' - }; - case TokenID.SUBSET_OR_EQ: return { - text: '⊆', - tooltip: 'быть частью (нестрогое подмножество) [Alt + 2]' - }; - case TokenID.SUBSET: return { - text: '⊂', - tooltip: 'строгое подмножество [Alt + 7]' - }; - case TokenID.NOTSUBSET: return { - text: '⊄', - tooltip: 'не подмножество [Alt + Shift + 2]' - }; - case TokenID.INTERSECTION: return { - text: '∩', - tooltip: 'пересечение [Alt + A]' - }; - case TokenID.UNION: return { - text: '∪', - tooltip: 'объединение [Alt + S]' - }; - case TokenID.SET_MINUS: return { - text: '\\', - tooltip: 'Разность множеств [Alt + 5]' - }; - case TokenID.SYMMINUS: return { - text: '∆', - tooltip: 'Симметрическая разность [Alt + Shift + 5]' - }; - case TokenID.NT_DECLARATIVE_EXPR: return { - text: 'D{}', - tooltip: 'Декларативная форма определения терма [Alt + D]' - }; - case TokenID.NT_IMPERATIVE_EXPR: return { - text: 'I{}', - tooltip: 'императивная форма определения терма [Alt + G]' - }; - case TokenID.NT_RECURSIVE_FULL: return { - text: 'R{}', - tooltip: 'рекурсивная (цикличная) форма определения терма [Alt + T]' - }; - case TokenID.BIGPR: return { - text: 'Pr1()', - tooltip: 'большая проекция [Alt + Q]' - }; - case TokenID.SMALLPR: return { - text: 'pr1()', - tooltip: 'малая проекция [Alt + W]' - }; - case TokenID.FILTER: return { - text: 'Fi1[]()', - tooltip: 'фильтр [Alt + F]' - }; - case TokenID.REDUCE: return { - text: 'red()', - tooltip: 'множество-сумма [Alt + R]' - }; - case TokenID.CARD: return { - text: 'card()', - tooltip: 'мощность [Alt + C]' - }; - case TokenID.BOOL: return { - text: 'bool()', - tooltip: 'синглетон [Alt + B]' - }; - case TokenID.DEBOOL: return { - text: 'debool()', - tooltip: 'десинглетон [Alt + V]' - }; - case TokenID.PUNC_ASSIGN: return { - text: ':=', - tooltip: 'присвоение (императивный синтаксис) [Alt + Shift + 6]' - }; - case TokenID.PUNC_ITERATE: return { - text: ':∈', - tooltip: 'перебор элементов множества (императивный синтаксис) [Alt + 6]' - }; - } - return { - text: 'undefined', - tooltip: 'undefined' - } -} - -export function getCstTypeLabel(type: CstType) { - switch (type) { - case CstType.BASE: return 'Базисное множество'; - case CstType.CONSTANT: return 'Константное множество'; - case CstType.STRUCTURED: return 'Родовая структура'; - case CstType.AXIOM: return 'Аксиома'; - case CstType.TERM: return 'Терм'; - case CstType.FUNCTION: return 'Терм-функция'; - case CstType.PREDICATE: return 'Предикат-функция'; - case CstType.THEOREM: return 'Теорема'; - } -} - -export function getCstTypeShortcut(type: CstType) { - const prefix = getCstTypeLabel(type) + ' [Alt + '; - switch (type) { - case CstType.BASE: return prefix + '1]'; - case CstType.STRUCTURED: return prefix + '2]'; - case CstType.TERM: return prefix + '3]'; - case CstType.AXIOM: return prefix + '4]'; - case CstType.FUNCTION: return prefix + 'Q]'; - case CstType.PREDICATE: return prefix + 'W]'; - case CstType.CONSTANT: return prefix + '5]'; - case CstType.THEOREM: return prefix + '6]'; - } -} - -export function getCstCompareLabel(mode: CstMatchMode): string { - switch(mode) { - case CstMatchMode.ALL: return 'везде'; - case CstMatchMode.EXPR: return 'выраж'; - case CstMatchMode.TERM: return 'термин'; - case CstMatchMode.TEXT: return 'текст'; - case CstMatchMode.NAME: return 'имя'; - } -} - -export function getDependencyLabel(mode: DependencyMode): string { - switch(mode) { - case DependencyMode.ALL: return 'вся схема'; - case DependencyMode.EXPRESSION: return 'выражение'; - case DependencyMode.OUTPUTS: return 'потребители'; - case DependencyMode.INPUTS: return 'поставщики'; - case DependencyMode.EXPAND_INPUTS: return 'влияющие'; - case DependencyMode.EXPAND_OUTPUTS: return 'зависимые'; - } -} - -export const mapLayoutLabels: Map = new Map([ - ['forceatlas2', 'Граф: Атлас 2D'], - ['forceDirected2d', 'Граф: Силы 2D'], - ['forceDirected3d', 'Граф: Силы 3D'], - ['treeTd2d', 'Граф: ДеревоВерт 2D'], - ['treeTd3d', 'Граф: ДеревоВерт 3D'], - ['treeLr2d', 'Граф: ДеревоГор 2D'], - ['treeLr3d', 'Граф: ДеревоГор 3D'], - ['radialOut2d', 'Граф: Радиальная 2D'], - ['radialOut3d', 'Граф: Радиальная 3D'], - ['circular2d', 'Граф: Круговая'], - ['hierarchicalTd', 'Граф: ИерархияВерт'], - ['hierarchicalLr', 'Граф: ИерархияГор'], - ['nooverlap', 'Граф: Без перекрытия'] -]); - -export const mapColoringLabels: Map = new Map([ - ['none', 'Цвет: моно'], - ['status', 'Цвет: статус'], - ['type', 'Цвет: класс'], -]); - -export function getCstStatusBgColor(status: ExpressionStatus, colors: IColorTheme): string { - switch (status) { - case ExpressionStatus.VERIFIED: return colors.bgGreen; - case ExpressionStatus.INCORRECT: return colors.bgRed; - case ExpressionStatus.INCALCULABLE: return colors.bgOrange; - case ExpressionStatus.PROPERTY: return colors.bgTeal; - case ExpressionStatus.UNKNOWN: return colors.bgBlue; - case ExpressionStatus.UNDEFINED: return colors.bgBlue; - } -} - -export function getCstStatusFgColor(status: ExpressionStatus, colors: IColorTheme): string { - switch (status) { - case ExpressionStatus.VERIFIED: return colors.fgGreen; - case ExpressionStatus.INCORRECT: return colors.fgRed; - case ExpressionStatus.INCALCULABLE: return colors.fgOrange; - case ExpressionStatus.PROPERTY: return colors.fgTeal; - case ExpressionStatus.UNKNOWN: return colors.fgBlue; - case ExpressionStatus.UNDEFINED: return colors.fgBlue; - } -} - -export const mapStatusInfo: Map = new Map([ - [ ExpressionStatus.VERIFIED, { - text: 'ок', - tooltip: 'выражение корректно и вычислимо' - }], - [ ExpressionStatus.INCORRECT, { - text: 'ошибка', - tooltip: 'ошибка в выражении' - }], - [ ExpressionStatus.INCALCULABLE, { - text: 'невыч', - tooltip: 'выражение не вычислимо' - }], - [ ExpressionStatus.PROPERTY, { - text: 'св-во', - tooltip: 'можно проверить принадлежность, но нельзя получить значение' - }], - [ ExpressionStatus.UNKNOWN, { - text: 'неизв', - tooltip: 'требует проверки выражения' - }], - [ ExpressionStatus.UNDEFINED, { - text: 'N/A', - tooltip: 'произошла ошибка при проверке выражения' - }] -]); - -export const mapTopicInfo: Map = new Map([ - [ HelpTopic.MAIN, { - text: 'Портал', - tooltip: 'Общая справка по порталу' - }], - [ HelpTopic.RSLANG, { - text: 'Рода структур', - tooltip: 'Справка по языку родов структур и экспликации' - }], - [ HelpTopic.LIBRARY, { - text: 'Библиотека', - tooltip: 'Интерфейс работы с библиотекой схем' - }], - [ HelpTopic.RSFORM, { - text: '- паспорт схемы', - tooltip: 'Интерфейс работы с описанием схемы' - }], - [ HelpTopic.CSTLIST, { - text: '- список конституент', - tooltip: 'Интерфейс работы со списком конституент' - }], - [ HelpTopic.CONSTITUENTA, { - text: '- конституента', - tooltip: 'Интерфейс редактирования конституенты' - }], - [ HelpTopic.GRAPH_TERM, { - text: '- граф термов', - tooltip: 'Интерфейс работ с графом термов схемы' - }], - [ HelpTopic.EXTEOR, { - text: 'Экстеор', - tooltip: 'Справка по программе Экстеор' - }], - [ HelpTopic.API, { - text: 'REST API', - tooltip: 'Документация интерфейса для разработчиков' - }], -]); - -export function getCstClassColor(cstClass: CstClass, colors: IColorTheme): string { - switch (cstClass) { - case CstClass.BASIC: return colors.bgGreen; - case CstClass.DERIVED: return colors.bgBlue; - case CstClass.STATEMENT: return colors.bgRed; - case CstClass.TEMPLATE: return colors.bgTeal; - } -} - -export const mapCstClassInfo: Map = new Map([ - [ CstClass.BASIC, { - text: 'базовый', - tooltip: 'неопределяемое понятие, требует конвенции' - }], - [ CstClass.DERIVED, { - text: 'производный', - tooltip: 'выводимое понятие, задаваемое определением' - }], - [ CstClass.STATEMENT, { - text: 'утверждение', - tooltip: 'неопределяемое понятие, требует конвенции' - }], - [ CstClass.TEMPLATE, { - text: 'шаблон', - tooltip: 'параметризованный шаблон определения' - }], -]); - -export function createAliasFor(type: CstType, schema: IRSForm): string { - const prefix = getCstTypePrefix(type); - if (!schema.items || schema.items.length <= 0) { - return `${prefix}1`; - } - const index = schema.items.reduce((prev, cst, index) => { - if (cst.cst_type !== type) { - return prev; - } - index = Number(cst.alias.slice(1 - cst.alias.length)) + 1; - return Math.max(prev, index); - }, 1); - return `${prefix}${index}`; -} - -export function getMockConstituenta(schema: number, id: number, alias: string, type: CstType, comment: string): IConstituenta { - return { - id: id, - order: -1, - schema: schema, - alias: alias, - convention: comment, - cst_type: type, - term_raw: '', - term_resolved: '', - term_forms: [], - definition_formal: '', - definition_raw: '', - definition_resolved: '', - status: ExpressionStatus.INCORRECT, - is_template: false, - cst_class: CstClass.DERIVED, - parse: { - status: ParsingStatus.INCORRECT, - valueClass: ValueClass.INVALID, - typification: 'N/A', - syntaxTree: '', - args: [] - } - }; -} - -export function getCloneTitle(schema: IRSForm): string { - if (!schema.title.includes('[клон]')) { - return schema.title + ' [клон]'; - } else { - return (schema.title + '+'); - } -} - -export function getTypificationLabel({isValid, resultType, args}: { - isValid: boolean, - resultType: string, - args: IFunctionArg[] -}): string { - if (!isValid) { - return 'N/A'; - } - if (resultType === '' || resultType === 'LOGIC') { - resultType = 'Logical'; - } - if (args.length === 0) { - return resultType; - } - const argsText = args.map(arg => arg.typification).join(', '); - return `${resultType} 🠔 [${argsText}]`; -} - -export function getCstTypificationLabel(cst: IConstituenta): string { - return getTypificationLabel({ - isValid: cst.parse.status === ParsingStatus.VERIFIED, - resultType: cst.parse.typification, - args: cst.parse.args - }); -} - -export function getRSErrorPrefix(error: IRSErrorDescription): string { - const id = error.errorType.toString(16) - switch(resolveErrorClass(error.errorType)) { - case RSErrorClass.LEXER: return 'L' + id; - case RSErrorClass.PARSER: return 'P' + id; - case RSErrorClass.SEMANTIC: return 'S' + id; - case RSErrorClass.UNKNOWN: return 'U' + id; - } -} - -export function getRSErrorMessage(error: IRSErrorDescription): string { - switch (error.errorType) { - case RSErrorType.syntax: - return 'Неопределенная синтаксическая ошибка'; - case RSErrorType.missingParanthesis: - return 'Некорректная конструкция языка родов структур, проверьте структуру выражения'; - case RSErrorType.missingCurlyBrace: - return "Пропущен символ '}'"; - case RSErrorType.invalidQuantifier: - return 'Некорректная кванторная декларация'; - case RSErrorType.expectedArgDeclaration: - return 'Ожидалось объявление аргументов терм-функции'; - case RSErrorType.expectedLocal: - return 'Ожидалось имя локальной переменной'; - - case RSErrorType.localDoubleDeclare: - return `Предупреждение! Повторное объявление локальной переменной ${error.params[0]}`; - case RSErrorType.localNotUsed: - return `Предупреждение! Переменная объявлена, но не использована: ${error.params[0]}`; - case RSErrorType.localUndeclared: - return `Использование необъявленной переменной: ${error.params[0]}`; - case RSErrorType.localShadowing: - return `Повторное объявление переменной: ${error.params[0]}`; - - case RSErrorType.typesNotEqual: - return `Типизация операндов не совпадает! ${error.params[0]} != ${error.params[1]}`; - case RSErrorType.globalNotTyped: - return `Типизация конституенты не определена: ${error.params[0]}`; - case RSErrorType.invalidDecart: - return `τ(α×b) = ℬ(𝔇τ(α)×𝔇τ(b)). Некорректная типизация аргумента: ${error.params[0]}`; - case RSErrorType.invalidBoolean: - return `τ(ℬ(a)) = ℬℬ𝔇τ(a). Некорректная типизация аргумента: ${error.params[0]}`; - case RSErrorType.invalidTypeOperation: - return `Типизация операнда теоретико-множественной операции не корректна: ${error.params[0]}`; - case RSErrorType.invalidCard: - return `Некорректная типизация аргумента операции мощности: ${error.params[0]}`; - case RSErrorType.invalidDebool: - return `τ(debool(a)) = 𝔇τ(a). Некорректная типизация аргумента: ${error.params[0]}`; - case RSErrorType.globalFuncMissing: - return `Неизвестное имя функции: ${error.params[0]}`; - case RSErrorType.globalFuncWithoutArgs: - return `Некорректное использование имени функции без аргументов: ${error.params[0]}`; - case RSErrorType.invalidReduce: - return `τ(red(a)) = ℬ𝔇𝔇τ(a). Некорректная типизация аргумента: ${error.params[0]}`; - case RSErrorType.invalidProjectionTuple: - return `Проекция не определена: ${error.params[0]} -> ${error.params[1]}`; - case RSErrorType.invalidProjectionSet: - return `τ(Pri(a)) = ℬ𝒞i𝔇τ(a). Некорректная типизация аргумента: ${error.params[0]}`; - case RSErrorType.invalidEnumeration: - return `Типизация аргументов перечисления не совпадает: ${error.params[0]} != ${error.params[1]}`; - case RSErrorType.ivalidBinding: - return `Количество переменных в кортеже не соответствует размерности декартова произведения`; - case RSErrorType.localOutOfScope: - return `Использование имени переменной вне области действия: ${error.params[0]}`; - case RSErrorType.invalidElementPredicat: - return `Несоответствие типизаций операндов для оператора: ${error.params[0]}${error.params[1]}${error.params[2]}`; - case RSErrorType.invalidArgsArtity: - return `Неверное число аргументов терм-функции: ${error.params[0]} != ${error.params[1]}`; - case RSErrorType.invalidArgumentType: - return `Типизация аргумента терм-функции не соответствует объявленной: ${error.params[0]} != ${error.params[1]}`; - case RSErrorType.invalidEqualsEmpty: - return `Только множества можно сравнивать с пустым множеством: ${error.params[0]}`; - case RSErrorType.globalStructure: - return `Выражение родовой структуры должно быть ступенью`; - case RSErrorType.globalExpectedFunction: - return `Ожидалось выражение объявления функции`; - case RSErrorType.emptySetUsage: - return `Запрещено использование пустого множества как типизированного выражения`; - case RSErrorType.radicalUsage: - return `Радикалы запрещены вне деклараций терм-функции: ${error.params[0]}`; - case RSErrorType.invalidFilterArgumentType: - return `Типизация аргумента фильтра не корректна: ${error.params[0]}(${error.params[1]})`; - case RSErrorType.invalidFilterArity: - return `Количество параметров фильтра не соответствует количеству индексов`; - case RSErrorType.arithmeticNotSupported: - return `Тип не поддерживает арифметические операторы: ${error.params[0]}`; - case RSErrorType.typesNotCompatible: - return `Типы не совместимы для выбранной операции: ${error.params[0]} и ${error.params[1]}`; - case RSErrorType.orderingNotSupported: - return `Тип не поддерживает предикаты порядка: ${error.params[0]}`; - case RSErrorType.globalNoValue: - return `Используется неинтерпретируемый глобальный идентификатор: ${error.params[0]}`; - case RSErrorType.invalidPropertyUsage: - return `Использование неитерируемого множества в качестве значения`; - case RSErrorType.globalMissingAST: - return `Не удалось получить дерево разбора для глобального идентификатора: ${error.params[0]}`; - case RSErrorType.globalFuncNoInterpretation: - return `Функция не интерпретируется для данных аргументов`; - case RSErrorType.globalNonemptyBase: - return `Непустое выражение базисного/константного множества`; - case RSErrorType.globalUnexpectedType: - return `Типизация выражения не соответствует типу конституенты`; - } - return 'UNKNOWN ERROR'; -} - -export function getASTNodeLabel(node: ISyntaxTreeNode): string { - switch(node.typeID) { - case TokenID.ID_LOCAL: - case TokenID.ID_GLOBAL: - case TokenID.ID_FUNCTION: - case TokenID.ID_PREDICATE: - case TokenID.ID_RADICAL: - return node.data.value as string; - - case TokenID.LIT_INTEGER: return String(node.data.value as number); - - case TokenID.BIGPR: return 'Pr' + (node.data.value as string[]).toString(); - case TokenID.SMALLPR: return 'pr' + (node.data.value as string[]).toString(); - case TokenID.FILTER: return 'Fi' + (node.data.value as string[]).toString(); - - case TokenID.PLUS: return '+' - case TokenID.MINUS: return '-' - case TokenID.MULTIPLY: return '*' - case TokenID.GREATER: return '>' - case TokenID.LESSER: return '<' - - case TokenID.NT_TUPLE: return 'TUPLE' - case TokenID.NT_ENUMERATION: return 'ENUM' - - case TokenID.NT_ENUM_DECL: return 'ENUM_DECLARATION' - case TokenID.NT_TUPLE_DECL: return 'TUPLE_DECLARATION' - case TokenID.PUNC_DEFINE: return 'DEFINITION' - case TokenID.PUNC_STRUCT: return 'STRUCTURE_DEFITION' - - case TokenID.NT_ARG_DECL: return 'ARG' - case TokenID.NT_FUNC_CALL: return 'CALL' - case TokenID.NT_ARGUMENTS: return 'ARGS' - - case TokenID.NT_FUNC_DEFINITION: return 'FUNCTION_DEFINITION' - case TokenID.NT_IMP_DECLARE: return 'IDECLARE' - case TokenID.NT_IMP_ASSIGN: return 'IASSIGN' - case TokenID.NT_IMP_LOGIC: return 'ICHECK' - - case TokenID.NT_RECURSIVE_SHORT: return getRSButtonData(TokenID.NT_RECURSIVE_FULL).text; - - case TokenID.BOOLEAN: - case TokenID.DECART: - case TokenID.FORALL: - case TokenID.EXISTS: - case TokenID.NOT: - case TokenID.AND: - case TokenID.OR: - case TokenID.IMPLICATION: - case TokenID.EQUIVALENT: - case TokenID.LIT_EMPTYSET: - case TokenID.LIT_INTSET: - case TokenID.EQUAL: - case TokenID.NOTEQUAL: - case TokenID.GREATER_OR_EQ: - case TokenID.LESSER_OR_EQ: - case TokenID.IN: - case TokenID.NOTIN: - case TokenID.SUBSET_OR_EQ: - case TokenID.SUBSET: - case TokenID.NOTSUBSET: - case TokenID.INTERSECTION: - case TokenID.UNION: - case TokenID.SET_MINUS: - case TokenID.SYMMINUS: - case TokenID.NT_DECLARATIVE_EXPR: - case TokenID.NT_IMPERATIVE_EXPR: - case TokenID.NT_RECURSIVE_FULL: - case TokenID.REDUCE: - case TokenID.CARD: - case TokenID.BOOL: - case TokenID.DEBOOL: - case TokenID.PUNC_ASSIGN: - case TokenID.PUNC_ITERATE: - return getRSButtonData(node.typeID).text; - } - // node - return 'UNKNOWN ' + String(node.typeID); -} - -export function getASTNodeColor(node: ISyntaxTreeNode, colors: IColorTheme): string { - switch(node.typeID) { - case TokenID.PUNC_DEFINE: - case TokenID.PUNC_STRUCT: - case TokenID.ID_LOCAL: - return colors.bgGreen; - - case TokenID.ID_GLOBAL: - case TokenID.ID_FUNCTION: - case TokenID.ID_PREDICATE: - case TokenID.ID_RADICAL: - case TokenID.LIT_INTEGER: - case TokenID.LIT_EMPTYSET: - case TokenID.LIT_INTSET: - return colors.bgTeal; - - case TokenID.FORALL: - case TokenID.EXISTS: - case TokenID.NOT: - case TokenID.AND: - case TokenID.OR: - case TokenID.IMPLICATION: - case TokenID.EQUIVALENT: - case TokenID.GREATER: - case TokenID.LESSER: - case TokenID.EQUAL: - case TokenID.NOTEQUAL: - case TokenID.GREATER_OR_EQ: - case TokenID.LESSER_OR_EQ: - case TokenID.IN: - case TokenID.NOTIN: - case TokenID.SUBSET_OR_EQ: - case TokenID.SUBSET: - case TokenID.NOTSUBSET: - return colors.bgOrange; - - case TokenID.NT_TUPLE: - case TokenID.NT_ENUMERATION: - case TokenID.BIGPR: - case TokenID.SMALLPR: - case TokenID.FILTER: - case TokenID.PLUS: - case TokenID.MINUS: - case TokenID.MULTIPLY: - case TokenID.BOOLEAN: - case TokenID.DECART: - case TokenID.INTERSECTION: - case TokenID.UNION: - case TokenID.SET_MINUS: - case TokenID.SYMMINUS: - case TokenID.REDUCE: - case TokenID.CARD: - case TokenID.BOOL: - case TokenID.DEBOOL: - return colors.bgBlue; - - case TokenID.NT_FUNC_DEFINITION: - case TokenID.NT_DECLARATIVE_EXPR: - case TokenID.NT_IMPERATIVE_EXPR: - case TokenID.NT_RECURSIVE_FULL: - case TokenID.NT_ENUM_DECL: - case TokenID.NT_TUPLE_DECL: - case TokenID.NT_ARG_DECL: - case TokenID.NT_FUNC_CALL: - case TokenID.NT_ARGUMENTS: - case TokenID.NT_IMP_DECLARE: - case TokenID.NT_IMP_ASSIGN: - case TokenID.NT_IMP_LOGIC: - case TokenID.NT_RECURSIVE_SHORT: - return ''; - - case TokenID.PUNC_ASSIGN: - case TokenID.PUNC_ITERATE: - return colors.bgRed; - } - // node - return colors.bgRed; -} diff --git a/scripts/prod/UpdateProd.sh b/scripts/prod/UpdateProd.sh index de122dfc..6035c537 100644 --- a/scripts/prod/UpdateProd.sh +++ b/scripts/prod/UpdateProd.sh @@ -1,5 +1,11 @@ +COMPOSE_FILE="docker-compose-prod.yml" +BACKUP_SCRIPT="./scripts/prod/CreateBackup.sh" + git reset --hard git pull -/bin/bash ./scripts/prod/CreateBackup.sh -docker compose --file "docker-compose-prod.yml" up --build --detach -docker image prune --all --force \ No newline at end of file + +/bin/bash "${BACKUP_SCRIPT}" + +docker compose --file "${COMPOSE_FILE}" up --build --detach +docker image prune --all --force +docker compose --file "${COMPOSE_FILE}" restart \ No newline at end of file