From cdf73a3949a9e631198aaf573533ad3183fd3861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D0=B5=D0=BC=20=D0=9F=D0=BE=D0=B4=D0=B4?= =?UTF-8?q?=D1=83=D0=B1=D0=BD=D1=8B=D0=B9?= Date: Thu, 3 Aug 2023 16:40:32 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=D0=92=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=8C=20=D0=BE=D0=BF=D0=B8=D1=81=D1=8B=D0=B2?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20=D1=81=D0=B2=D1=8F=D0=B7=D0=B8=20=D0=B2=20?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=BE=D0=BC=20=D1=84=D0=BE=D1=80=D0=BC=D0=B0?= =?UTF-8?q?=D1=82=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/new_links_format/README.md | 43 +++ src/new_links_format/converter.jsonata | 26 ++ src/new_links_format/datasets/links.yaml | 24 ++ src/new_links_format/dochub.yaml | 4 + src/new_links_format/entites/links.yaml | 65 ++++ src/new_links_format/example.yaml | 143 +++++++ .../dochub/entities/contexts/base.yaml | 354 ++++++++++++++++++ .../dochub/entities/contexts/plantuml.yaml | 221 +++++++++++ 8 files changed, 880 insertions(+) create mode 100644 src/new_links_format/README.md create mode 100644 src/new_links_format/converter.jsonata create mode 100644 src/new_links_format/datasets/links.yaml create mode 100644 src/new_links_format/dochub.yaml create mode 100644 src/new_links_format/entites/links.yaml create mode 100644 src/new_links_format/example.yaml create mode 100644 src/new_links_format/metamodel/dochub/entities/contexts/base.yaml create mode 100644 src/new_links_format/metamodel/dochub/entities/contexts/plantuml.yaml diff --git a/src/new_links_format/README.md b/src/new_links_format/README.md new file mode 100644 index 0000000..43a325c --- /dev/null +++ b/src/new_links_format/README.md @@ -0,0 +1,43 @@ +# Пример модификации метамодели для описания связей в новом формате + +**Цель примера:** +1. Предоставить пример модификации метамодели +2. Предоставить новый способ описания связей между сущностями + +# Суть примера +В примере реализован новый вид описания связей между сущностями. Задействованы механизмы изменения метамодели, кастомных сущностей(entity) и датасетов. + +# Формат +Связь в данном примере описывается в следующем формате: +```yaml +links: + front.app-orders.backend: + from: front.app + to: orders.backend + via: + - orders.gateway + title: Передача заказа + contract: dh.contract.id + + front.web-orders.backend: + from: front.web + to: orders.backend + via: + - orders.gateway + title: Передача заказа +``` +Обязательными являются только параметры from/to. Новый параметр via позволяет отметить шлюз, через который работает связь между компонентами не создавая при этом двух отдельных сущностей. + +# Особенности +1. Связь между компонентами - это отдельный объект, который можно расширить. +2. Несколько связей между компонентами на схемах группируется в одну. При клике по такой связи мы попадаем на страницу со списком. +3. В SELF контексте компонента будут отображены все связи, которые у него существуют. Неважно при этом где они описаны. Также будут показаны связи, которые проходят через шлюзы. +4. Все связи всплывают наверх, если вы используете модель DDD, при всплытии также происходит группировка. +5. Работает ТОЛЬКО с plantUML представлением. + +# Подключение: +1. Заменить файлы, находящиеся в папке metamodel/dochub/entities/contexts на файлы в соотвествующей папке из примера. +2. Использовать converter.json, которые сделает первичную конвертацию из формата старых ссылок в новый формат. +3. Добавить полученные данные в свойство "links:" +4. Старые связи можно не удалять. + diff --git a/src/new_links_format/converter.jsonata b/src/new_links_format/converter.jsonata new file mode 100644 index 0000000..39ca206 --- /dev/null +++ b/src/new_links_format/converter.jsonata @@ -0,0 +1,26 @@ +( + $links := $.components.$spread().( + $id := $keys()[0]; + $l := *.links; + $l.( + $f := $contains(direction, "<"); + $f ? { + "from": id, + "to": $id, + "title": title, + "contract": contract + } : { + "from": $id, + "to": id, + "title": title, + "contract": contract + } + ) + ); + $links{from & "-" & to:{ + "from": from, + "to": to, + "title": title, + "contract": contract + }} +) diff --git a/src/new_links_format/datasets/links.yaml b/src/new_links_format/datasets/links.yaml new file mode 100644 index 0000000..aa82e97 --- /dev/null +++ b/src/new_links_format/datasets/links.yaml @@ -0,0 +1,24 @@ +datasets: + links: + source: > + ( + $c := $.components; + [ + $.links.$spread().( + $d:=*.$; + $contract := $d.contract ? "/entities/docs/blank?dh-doc-id=" & $d.contract : ""; + $from := $lookup($c, $d.from); + $to := $lookup($c, $d.to); + $url := $d.title; + { + "about": $url, + "from_link": "/architect/components/" & $d.from, + "to_link": "/architect/components/" & $d.to, + "from": $d.from, + "to": $d.to, + "via": $d.via, + "contract": $contract + } + ) + ] + ) \ No newline at end of file diff --git a/src/new_links_format/dochub.yaml b/src/new_links_format/dochub.yaml new file mode 100644 index 0000000..6464d53 --- /dev/null +++ b/src/new_links_format/dochub.yaml @@ -0,0 +1,4 @@ +imports: + - entites/links.yaml + - datasets/links.yaml + - example.yaml \ No newline at end of file diff --git a/src/new_links_format/entites/links.yaml b/src/new_links_format/entites/links.yaml new file mode 100644 index 0000000..4bd3563 --- /dev/null +++ b/src/new_links_format/entites/links.yaml @@ -0,0 +1,65 @@ +entities: + links: + menu: > + ( + [{ + "location": "Документы/Взаимодействия", + "link": "entities/links/mainlist" + }] + ) + schema: + properties: + tables: + type: object + patternProperties: + # Определяем шаблон идентификаторов контекстов + ^([a-zA-Z\\_0-9]*)\.([a-zA-Z\_0-9]*).([a-zA-Z\_0-9]*)$: + type: object + properties: + description: + type: string + owners: + type: array + required: + - description + - owners + presentations: + filtered: + type: table + headers: + - value: about + text: Описание взаимодействия + sortable: true + link: contract + - value: from + text: От + sortable: true + link: from_link + - value: to + text: К + sortable: true + link: to_link + origin: links + source: > + ( + $from := $params.from != "" ? $params.from : ""; + $to := $params.to != "" ? $params.to : ""; + [$[$contains(from, $from) and $contains(to, $to)]] + ) + mainlist: + type: table + headers: + - value: about + text: Описание взаимодействия + sortable: true + link: contract + - value: from + text: От + sortable: true + link: from_link + - value: to + text: К + sortable: true + link: to_link + origin: links + source: ($) \ No newline at end of file diff --git a/src/new_links_format/example.yaml b/src/new_links_format/example.yaml new file mode 100644 index 0000000..ea00b38 --- /dev/null +++ b/src/new_links_format/example.yaml @@ -0,0 +1,143 @@ +links: + front.app-orders.backend: + from: front.app + to: orders.backend + via: + - orders.gateway + title: Передача заказа + + front.web-orders.backend: + from: front.web + to: orders.backend + via: + - orders.gateway + title: Передача заказа + + front.app-auth.backend: + from: front.app + to: auth.backend + via: + - auth.gateway + title: Авторизация + + front.web-auth.backend: + from: front.web + to: auth.backend + via: + - auth.gateway + title: Авторизация + + orders.backend-payments.backend: + from: orders.backend + to: payments.backend + via: + - payments.gateway + title: Оплата + payments.backend-payments.db: + from: payments.backend + to: payments.db + + orders.backend-orders.db: + from: orders.backend + to: orders.db + + orders.backend-auth.backend: + from: orders.backend + to: auth.backend + title: Авторизация + contract: notfounddocument + + auth.backend-auth.db: + from: auth.backend + to: auth.db + +components: + # Описываем L2 + + # ************************************** + # Платежный шлюз (payments) + # ************************************** + # Здесь даем общую информацию о системе. + # Детали будем собирать автоматически из L2 + payments: + title: Платежи + entity: component + + # Подробно описываем L2 + payments.gateway: + title: Шлюз + entity: component + payments.backend: + title: Микросервис оплаты + entity: component + links: + - id: payments.db + payments.db: + title: База платежей + entity: database + + # ************************************** + # Подсистема заказов (orders) + # ************************************** + # Аналогично, даем общую информацию + orders: + title: Заказы + entity: component + + # Подробно описываем L2 + orders.gateway: + title: Шлюз + entity: component + orders.backend: + title: Микросервис заказов + entity: component + orders.db: + title: База заказов + entity: database + + # ************************************** + # Подсистема авторизации (auth) + # ************************************** + auth: + title: Авторизация + entity: component + auth.gateway: + title: Шлюз + entity: component + auth.backend: + title: Микросервис авторизации + entity: component + auth.db: + title: База пользователей + entity: database + + # ************************************** + # Фронтэнд (front) + # ************************************** + # Пользовательское приложение + front: + title: Фронтальные компоненты + entity: component + + front.web: + entity: component + title: Веб-сайт + + front.app: + entity: component + title: Приложение + +contexts: + L2: + title: L2 уровень + location: L2 + components: + - "*.*" # Отбираем все компоненты второго уровня + L1: + title: L1 уровень + location: L1 + components: + - front + - auth + - orders + - payments \ No newline at end of file diff --git a/src/new_links_format/metamodel/dochub/entities/contexts/base.yaml b/src/new_links_format/metamodel/dochub/entities/contexts/base.yaml new file mode 100644 index 0000000..15965c8 --- /dev/null +++ b/src/new_links_format/metamodel/dochub/entities/contexts/base.yaml @@ -0,0 +1,354 @@ +# Базовое описание сущности "Contexts" +entities: + contexts: + title: Контексты + description: > + Представлять указанные архитектурные компоненты в виде диаграмм. + schema: + type: object + patternProperties: + "^[a-zA-Z][a-zA-Z0-9_-]*(\\.[a-zA-Z][a-zA-Z0-9_-]*)*$": + type: object + properties: + title: + title: Название контекста + type: string + location: + title: Место расположения в меню + type: string + icon: + title: Иконка в меню + type: string + components: + title: Комппоненты контекста + type: array + items: + type: string + title: Идентификатор компонента или маска + pattern: "^[a-zA-Z][a-zA-Z0-9\\_]*(\\.([a-zA-Z][a-zA-Z0-9\\_]*|\\*))*$" + extra-links: + title: Отображать компоненты ближайших связей + type: boolean + presentation: + title: Принудительно определяет презентацию + type: string + enum: + - plantuml + - smartants + uml: + title: Кастомизация контекста + oneOf: + - type: string + title: Путь к файлу PlantUML + - type: object + title: Дополнительные параметры + properties: + $before: + title: Код встраиваемый до сгенерированного + type: string + $after: + title: Код встраиваемый после сгенерированного + type: string + api: + type: object + title: Переопределяемые API + properties: + fetchComponents: + type: string + title: Возвращает список компонентов в кормате ключ-значение + fetchLinks: + type: string + title: Возвращает список связей компонентов + source: + title: Источник данный (запрос или dataset) + type: string + anyOf: + - type: string + title: Идентификатор dataset + pattern: "^[a-zA-Z][a-zA-Z0-9\_]*(\\.[a-zA-Z][a-zA-Z0-9\\_]*)*$" + - type: string + title: JSONata запрос + pattern: "\\s*\\((.|\\s)*\\)\\s*" + required: + - title + - components + additionalProperties: false + # Определяет пути к объектам сущности + routes: + context: "/:id" # Путь к контексту + menu: > + ( + $presentation := entities.contexts.config.defaultPresentation; + $append([ + { + "title": "Контексты", + "location": 'Архитектура/Контексты', + "icon": 'location_searching' + } + ], + contexts.$spread().( + /* Если указана явно презентация, используем ее */ + $presentation := $.*.presentation ? *.presentation : $presentation; + *.location ? { + "location": "Архитектура/Контексты/" & *.location, + "link": "entities/contexts/" & $presentation & "?dh-context-id=" & $keys()[0] + } + ) + ); + ) + # Предопределенные конфигурационные параметры для генерации контекстов + config: + # Идентификатор презентации по умолчанию + defaultPresentation: plantuml # plantuml / smartants + # Общие API функции для генерирования контекста + api: + # Возввращает компоненты входящие в контекст + # Входящие параметры: + # manifest - данные архитектуры + # contextId - идентификатор контекста + # extra-links - признак необходимости отразить окружение + # componentId - идентификатор компонента для контекста SELF + fetchComponents: > + ( + /* Обрабатываем параметры */ + $params := $; + $manifest := $params.manifest; + /* Признак SELF контекста */ + $isSelf := $params.componentId ? true : false; + /* Получаем объект контекста */ + $context := $lookup($params.manifest.contexts, contextId); + + /* Определяем необходимость показывать ближайшие связи */ + $isExtraLinks := $params.componentId ? true : $params."extra-links"; + /* Определяем, какие компоненты покажем в контексте */ + $showComponents := $params.componentId + /* Если контекст под определенный компонент, ограничиваемся им. */ + ? [$params.componentId] + /* Если нет берем все компоненты указанные в контексте */ + : $context.components; + + /* Если в контексте переопределена функция получения компонентов, используем ее*/ + $r := $context.api.fetchComponents ? ( + $eval($context.api.fetchComponents, $params) + ) : ( + /* Получаем все компоненты входящие в контекст */ + $components := $merge($showComponents.( + $mask := $; + $manifest.components.$spread().( + $componentId := $keys()[0]; + $result := $wcard($componentId, $mask) ? $ + ) + )); + ); + ) + # На основании списка компонентов генерирует массиа областей которые они затрагивают + # Входящие параметры: + # components - список компонентов в формате fetchComponents + fetchAreas: > + ( + $distinct(components.$spread().( + $componentId := $keys()[0]; + $domains := $componentId.$split("."); + $limit := $count($domains) - 1; + $areaId := $map($domains, function($v, $i) {( + $join($map($domains, function($sv, $si) { + $si <= $i ? $sv + }), ".") + )}); + ))^($); + ) + + oldFormToNew: > + ( + $.components.$spread().( + $from := $keys(); + $l := *.$; + $l.links.( + $f := direction = "<--" or direction = "<-" or direction = "<---" or direction = "<-----" ? id : $from; + $t := $f = id ? $from : id; + {"from": $f, "to":$t, "contract":$.contract, "title": $.title, "direction": "-->"} + ) + ) + ) + + # Генерирует список отображаемых связей + # Входящие параметры: + # components - список компонентов в формате fetchComponents + # links - список ссылок + # required - список компонентов, явно добавленных в контекст + fetchComponentsFromLinks: > + ( + $requiredComponents := required; + $components := components; + $links := links; + $neededComponents := $distinct($append($links.from, $links.to) ~> $append($requiredComponents.$keys())); + $neededComponents.( + $id := $; + {$id:$lookup($components, $id).{ + "title": title, + "entity": entity, + "aspects": aspects + }}; + ) + ) + fetchLinks: > + ( + $manifest := manifest; + $components := $manifest.components; + $cmp := [components.$keys()]; + $first := $cmp[0]; + $v := $cmp.( + $split($first, ".") ~> $count() = $split($, ".") ~> $count() ? true : false; + ); + $isDomainLevel:=$reduce($v, function($a, $b) {$a and $b}); + + $isExtraLinks := false; + $isExtraLinks:= $count($cmp) = 1 ? true : extraLinks; + + $domainLevel := $isDomainLevel ? $count($split($cmp[0], ".")); + + $rawLinks := $manifest.links.$spread().{ + "from": *.from, + "to": *.to, + "title": *.title, + "via": *.via, + "contract": *.contract + }; + + $c := $components.$spread().$keys().{"key":$}; + + $services := $cmp.( + $key:=$; + $c[($contains(key, $key) and $not($substringBefore(key, $key)))]{"list": key, "key": $key}; + ); + $l := $not($isExtraLinks) ? $rawLinks[from in $services.list and to in $services.list][from != to] : $rawLinks[from in $services.list or to in $services.list][from != to]; + + $links:= $l{from & "-" & to & "-" & via:{ + "from": [from], + "to": [to], + "via": [via], + "contract": [contract], + "title": [title], + "count": $count(from)} + }; + + $res := $links.$spread().( + $l := *.$; + $from := $l.from[0]; + $to := $l.to[0]; + $fromService := $domainLevel ? $split($from,".", $domainLevel) ~> $join(".") : ($services[$from in list])[0].key; + $toService := $domainLevel ? $split($to,".", $domainLevel) ~> $join(".") : ($services[$to in list])[0].key; + $count(*.via) > 0 ? ( + $data := [$from, *.via, $to]; + $data#$i.( + $fromVia := $; + $data[$i+1] ? ( + $toVia := $data[$i+1]; + $fromServiceVia := $domainLevel ? $split($fromVia,".", $domainLevel) ~> $join(".") : ($services[$fromVia in list])[0].key; + $toServiceVia := $domainLevel ? $split($toVia,".", $domainLevel) ~> $join(".") : ($services[$toVia in list])[0].key; + { + "realFrom": $from, + "realTo": $to, + "from": $fromServiceVia, + "to": $toServiceVia, + "from_query": $fromService, + "to_query": $toService, + "count": $l.count, + "via": $from & "-" & $to, + "contract": $l.contract, + "title": $l.title + } + ) + ) + ) : ( + { + "realFrom": $fromService, + "realTo": $toService, + "from": $fromService, + "to": $toService, + "from_query": $fromService, + "to_query": $toService, + "via": false, + "count": $l.count, + "contract": $l.contract, + "title": $l.title + } + ) + ); + + $mainRes :=[$res{from & "-" & to & "-" & via:{ + "realFrom": [realFrom], + "realTo": [realTo], + "from": [from], + "to": [to], + "from_query": [from_query], + "to_query": [to_query], + "via": via, + "count": $sum(count), + "title": [title], + "contract": contract + }}.$spread().( + $contract := (*.count > 1 or $not(*.contract)) ? "/entities/links/filtered?from=" & *.from_query[0] & "&to=" & *.to_query[0] : "/entities/docs/blank?dh-doc-id=" & *.contract[0]; + $fromServiceName := $lookup($components, *.from_query[0]).title; + $toServiceName := $lookup($components, *.to_query[0]).title; + $title := (*.count > 1 or $not(*.title)) ? ( + $fromServiceName & " -> " & $toServiceName & " (" & *.count & ")") : *.title[0]; + { + "realFrom": [*.realFrom], + "realTo": [*.realTo], + "from":*.from[0], + "fromServiceName":$fromServiceName, + "to": *.to[0], + "toServiceName":$toServiceName, + "count": *.count, + "via": *.via, + "direction": "-->", + "contract": $contract, + "title": $title + } + )][from != to]; + + $getMatched := function($array){( + $v1 := ($array)[0]; + $sv1 := $split($v1, "."); + $cnt := $count($sv1); + $rf := $array; + + $rfr := $sv1#$i.( + $matcher := $join($split($v1, ".", $cnt-$i),"."); + $res := $count([$filter($rf, function($v){ + $contains($v, $matcher) + })]); + { + "matcher": $matcher, + "num": $i, + "res": $res, + "crf": $count($rf) + } + ); + $rss:= $min($rfr[res=crf].num); + $q := $rfr[num=$rss].matcher; + $q; + )}; + + $r:=$mainRes{from & "-" & to: ( + $lFrom := $getMatched(realFrom); + $lTo := $getMatched(realTo); + $values := $count(from); + $cnt := $sum(count); + $contract := $values > 1 ? "/entities/links/filtered?from=" & $lFrom & "&to=" & $lTo : contract; + $to := (to)[0]; + $title := $values > 1 ? ( + $r:=$domainLevel ? $split($to,".", $domainLevel) ~> $join(".") : ($services[$to in list])[0]; + (fromServiceName)[0] & " -> " & ($lookup($components, $r).title)[0] & " (" & $cnt & ")" + ) : title; + { + "from":(from)[0], + "to": (to)[0], + "count": $cnt, + "direction": (direction)[0], + "contract": $contract, + "title": $title + } + )}.$spread().* + ) \ No newline at end of file diff --git a/src/new_links_format/metamodel/dochub/entities/contexts/plantuml.yaml b/src/new_links_format/metamodel/dochub/entities/contexts/plantuml.yaml new file mode 100644 index 0000000..0773cbd --- /dev/null +++ b/src/new_links_format/metamodel/dochub/entities/contexts/plantuml.yaml @@ -0,0 +1,221 @@ +# Расширение сущности "Contexts" для генерации PlantUML диаграмм +entities: + contexts: + # Предопределенные конфигурационные параметры для генерации PlantUML + config: + # Какой движок будет использоваться для рендера + renderCore: elk # elk / smetana / graphviz + # API функции, используемые для генерации PlantUML + api: + # Генерирует на данных о компонентах и областях PlantUML диаграмму компонентов + # Входящие параметры: + # manifest - данные архитектуры + # components - список компонентов в формате fetchComponents + # areas - список компонентов в формате fetchAreas + makePumlComponentDiagram: > + ( + /* Обрабатываем параметры */ + $areas := areas; + $components := components; + $manifest := manifest; + + $stopBracketsCount := function($a, $b) {$a = 0 ? "}\n" : $a & "}\n"}; + + $join($map($areas, function($domain, $index) {( + $result := ""; + $component := $lookup($components, $domain); + $originComponent := $lookup($manifest.components, $domain); + $context := $lookup($manifest.contexts, $domain); + + /* Определяем является ли элемент областью */ + $isAreaBegin := $areas[$index + 1].$substring(0, $domain.$length() + 1) = $domain & "."; + + $result := $result & ($isAreaBegin ? ( + $title := $originComponent.title ? $originComponent.title : ( + $context.title ? $context.title : $domain + ); + "$Region(" + & $domain + & ",\"[[/architect/components/" + & $domain + & " " & $title + & "]]\", ) {\n"; + ) : ""); + + /* Если домен является компонентом, выводим его на диаграмму */ + $result := $result & ( + $not($isAreaBegin) and $component ? ( + /* Открываем секцию компонента */ + $entity := $component.entity ? $component.entity : "component"; + $result := "$Entity(\"" + & $entity + & "\", \"" + & "[[/architect/components/" & $domain & " " & $component.title & "]]" + & "\", " + & $domain + & ", )\n"; + + /* Добавляем аспекты */ + $result := $result & $join($component.aspects.( + $aspect := $lookup($manifest.aspects, $); + $title := $aspect ? $aspect.title : $; + "$EntityAspect(\"" + & $entity + & "\",\"[[/architect/aspects/" + & $ + & " " + & $title + & "]]\")\n" + )); + + /* Если компонент является контекстом добавляем дрилдаун */ + $context ? + $result := $result & "$EntityExpand(\"" + & $entity + & "\", " + & $domain + & ")\n"; + + /* Закрываем секцию компонента */ + $result := $result & + "$EntityEnd(\"" + & $entity + & "\")\n"; + ): ""; + ); + + /* Определяем, что область нужно закрыть*/ + $result & ( + $count($split($domain, ".")) > 1 + and ($count($split($domain, ".")) > $count($split($areas[$index + 1], ".")) + ) ? ( + $m := $areas[$index + 1] ? 0 : -1; + $reduce([0..($count($split($domain, ".")) - $count($split($areas[$index + 1], ".")) + $m)], $stopBracketsCount); + ) : ""); + )})); + ) + # Генерирует PlantUML код связей для диаграммы компонентов + # Входящие параметры: + # links - список связей в формате fetchLinks + makePumlComponentsLinks: > + ( + $join(links.( + from & " " & direction & " " & to & (title ? ": [[" & contract & " " & title & "]]" : "") & "\n" + )) + ) + # Представления контекстов в PlantUML + presentations: + plantuml: + title: Представление в PlantUML + params: + title: Требуемые параметры для презентации + type: object + properties: + "dh-context-id": + title: Идентификатор контекста + type: string + pattern: ^[a-zA-Z][a-zA-Z0-9_-]*(\.[a-zA-Z][a-zA-Z0-9_-]*)*$ + required: + - dh-context-id + type: plantuml + $constructor: > # Переносим необходимую информацию из контекста в презентацию + ( + $id := $params."dh-context-id"; + $context := $lookup(contexts, $id); + $prototype := entities.contexts.presentations.plantuml; + + /* Преобразует относительные пути к файлам в прямые*/ + $toDirectRes := function($value) { + $substring($value, 0, 4) = "res:" ? $value : "res://contexts/" & $id & "#" & $value + }; + + /* Если явно указан puml файл, просто рендерим его */ + ($type($context.uml) = "string") and ($substring($context.uml, -5) = ".puml") ? ( + { + "type": "plantuml", + "source": $toDirectRes($context.uml) + } + ) : ( + $result := $context.source ? ($merge([$prototype, { + "origin": { "_source": $context.source, "_origin": "($)" } + }])) : $prototype; + + /* Если в контексте переопределен шаблон, используем его по прямой ссылке */ + $result := $context.template + ? $merge([$result, { "template": $toDirectRes($context.template) }]) + : $result; + ) + ) + template: templates/template.puml + source: > + ( + $id := $params."dh-context-id"; + /* Получаем доступ к оригинальным данным */ + $manifest := _origin ? _origin : $; + /* Получаем контекст */ + $context := $lookup($manifest.contexts, $id); + /* Если в контексте задан источник, берем его за основу */ + $manifest := _source ? _source : $; + + $isExtraLinks := $not($string($context."extra-links") = "false"); + + /* Получаем коллекцию дефолтных вспомогательных функций */ + $defFunctions := $manifest.entities.contexts.api; + + /* Получаем коллекцию дефолтных параметров */ + $defConfig := $manifest.entities.contexts.config; + + /* Определяем движок рендеринга */ + $renderCore := $lookup({ + "elk": "!pragma layout elk", + "smetana": "!pragma layout smetana" + }, $defConfig.renderCore); + + /* Формируем заголовок */ + $header := "$Header(\"" & ($context.title ? $context.title : $id ) & "\", \"" & $context.uml."$autor" & "\", \"" & $context.uml."$version" & "\" , \"" & $context.uml."$moment" & "\")\n"; + + /* Получаем все компоненты входящие в контекст */ + $components := $eval($defFunctions.fetchComponents, { + "manifest": $manifest, + "contextId": $id, + "componentId": $params.componentId + }); + + /* Получаем список связей */ + $links := $eval($context.api.fetchLinks ? $context.api.fetchLinks : $defFunctions.fetchLinks, { + "manifest": $manifest, + "extraLinks": $isExtraLinks, + "components": $components + }); + + $components := $eval($defFunctions.fetchComponentsFromLinks, { + "links": $links, + "components": $manifest.components, + "required": $components + }); + + /* Генерируем области */ + $areas := $eval($defFunctions.fetchAreas, { + "components": $components + }); + + /* Генерируем PlantUML диаграмму компонентов */ + $elements := $eval($defFunctions.makePumlComponentDiagram, { + "manifest": $manifest, + "areas": $areas, + "components": $components + }); + + + /* Генерируем код связей */ + $linksCode := $eval($defFunctions.makePumlComponentsLinks, { + "links": $links + }); + + /* Готовим данные для передачи в шаблон */ + { + "renderCore": $renderCore, + "presentation": $defConfig.defaultPresentation, + "code": $header & $elements & $linksCode + } + ) From 322c43e500717edb8f168b0980a6a5d969981fa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D0=B5=D0=BC=20=D0=9F=D0=BE=D0=B4=D0=B4?= =?UTF-8?q?=D1=83=D0=B1=D0=BD=D1=8B=D0=B9?= Date: Thu, 3 Aug 2023 17:45:14 +0300 Subject: [PATCH 2/2] Update README.md --- src/new_links_format/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/new_links_format/README.md b/src/new_links_format/README.md index 43a325c..94306ed 100644 --- a/src/new_links_format/README.md +++ b/src/new_links_format/README.md @@ -34,10 +34,12 @@ links: 3. В SELF контексте компонента будут отображены все связи, которые у него существуют. Неважно при этом где они описаны. Также будут показаны связи, которые проходят через шлюзы. 4. Все связи всплывают наверх, если вы используете модель DDD, при всплытии также происходит группировка. 5. Работает ТОЛЬКО с plantUML представлением. +6. Корректно работает в случае указания элемнтов разного уровня на контекстной диаграмме. При этом прозводительность упадет. # Подключение: 1. Заменить файлы, находящиеся в папке metamodel/dochub/entities/contexts на файлы в соотвествующей папке из примера. 2. Использовать converter.json, которые сделает первичную конвертацию из формата старых ссылок в новый формат. -3. Добавить полученные данные в свойство "links:" -4. Старые связи можно не удалять. +3. Подключить файлы entities/links.yaml и datasets/links.yaml в архитектуру +4. Добавить полученные данные в свойство "links:" +5. Старые связи можно не удалять