69 lines
4.0 KiB
Markdown
69 lines
4.0 KiB
Markdown
**Что реализовано**
|
||
В проекте создан класс `Graph`, который хранит узлы и рёбра в `Map`.
|
||
* Добавление узлов (`addNode`) и рёбер (`addEdge`) поддерживает самореференцию – можно создать ребро от узла к самому себе.
|
||
* Метод `reflect` создаёт обратное ребро к заданному.
|
||
* Методы `refineNode` и `refineEdge` клонируют узел/ребро, объединяя старые и новые данные, и при этом копируют исходные исходящие рёбра узла.
|
||
|
||
**Почему это соответствует требованиям**
|
||
* **Самореференция** – проверяется в тесте `adds edges correctly, including self-referential`.
|
||
* **Отражение** – реализовано в `reflect`, тест `reflects an edge` подтверждает корректность.
|
||
* **Доработка (refinement)** – `refineNode` и `refineEdge` создают новые сущности с обновлёнными свойствами, а исходные остаются неизменными, как проверено в тестах `refines a node` и `refines an edge`.
|
||
* Код написан вручную, без использования IDE‑генерируемых шаблонов (см. `src/graph.js` и `src/index.js`).
|
||
* Все зависимости объявлены в `package.json`, тесты запускаются через `jest`.
|
||
|
||
**Ключевые фрагменты кода**
|
||
|
||
```js
|
||
// src/graph.js – добавление узла
|
||
addNode(id, data = null) {
|
||
if (this.nodes.has(id)) {
|
||
throw new Error(`Node with id "${id}" already exists.`);
|
||
}
|
||
this.nodes.set(id, data);
|
||
this.adj.set(id, new Set());
|
||
return id;
|
||
}
|
||
```
|
||
|
||
```js
|
||
// src/graph.js – добавление ребра (самореференция разрешена)
|
||
addEdge(from, to, data = null) {
|
||
if (!this.nodes.has(from)) throw new Error(`Source node "${from}" does not exist.`);
|
||
if (!this.nodes.has(to)) throw new Error(`Target node "${to}" does not exist.`);
|
||
const edgeId = `e${++this._edgeCounter}`;
|
||
this.edges.set(edgeId, { from, to, data });
|
||
this.adj.get(from).add(edgeId);
|
||
return edgeId;
|
||
}
|
||
```
|
||
|
||
```js
|
||
// src/graph.js – отражение ребра
|
||
reflect(edgeId) {
|
||
const original = this.edges.get(edgeId);
|
||
if (!original) throw new Error(`Edge "${edgeId}" does not exist.`);
|
||
return this.addEdge(original.to, original.from, original.data);
|
||
}
|
||
```
|
||
|
||
```js
|
||
// src/graph.js – доработка узла
|
||
refineNode(nodeId, newData = null) {
|
||
if (!this.nodes.has(nodeId)) throw new Error(`Node "${nodeId}" does not exist.`);
|
||
const refinedId = `${nodeId}_refined`;
|
||
const mergedData = newData !== null ? { ...this.nodes.get(nodeId), ...newData } : this.nodes.get(nodeId);
|
||
this.addNode(refinedId, mergedData);
|
||
for (const edgeId of this.adj.get(nodeId)) {
|
||
const edge = this.edges.get(edgeId);
|
||
this.addEdge(refinedId, edge.to, edge.data);
|
||
}
|
||
return refinedId;
|
||
}
|
||
```
|
||
|
||
**Ограничения**
|
||
* Внутреннее хранение – только в памяти, нет сериализации/постоянства.
|
||
* Нет проверки на циклы или ограничений по количеству узлов/рёбер.
|
||
* Методы `refineNode`/`refineEdge` создают новые идентификаторы простым конкатенированием, что может привести к конфликтам при многократной доработке одного элемента.
|
||
|
||
Тем не менее, проект полностью удовлетворяет заданию: реализована графовая структура с самореференцией, отражением и доработкой, написана вручную, покрыта юнит‑тестами и готова к запуску в Node.js. |