**Что реализовано** В проекте создан класс `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.