src/graph.js
function addEdge(
  graph,
  name,
  mustGenerateKey,
  undirected,
  edge,
  source,
  target,
  attributes
) {

  // Checking validity of operation
  if (!undirected && graph.type === 'undirected')
    throw new UsageGraphError(`Graph.${name}: you cannot add a directed edge to an undirected graph. Use the #.addEdge or #.addUndirectedEdge instead.`);

  if (undirected && graph.type === 'directed')
    throw new UsageGraphError(`Graph.${name}: you cannot add an undirected edge to a directed graph. Use the #.addEdge or #.addDirectedEdge instead.`);

  if (attributes && !isPlainObject(attributes))
    throw new InvalidArgumentsGraphError(`Graph.${name}: invalid attributes. Expecting an object but got "${attributes}"`);

  // Coercion of source & target:
  source = '' + source;
  target = '' + target;
  attributes = attributes || {};

  if (!graph.allowSelfLoops && source === target)
    throw new UsageGraphError(`Graph.${name}: source & target are the same ("${source}"), thus creating a loop explicitly forbidden by this graph 'allowSelfLoops' option set to false.`);

  const sourceData = graph._nodes.get(source),
        targetData = graph._nodes.get(target);

  if (!sourceData)
    throw new NotFoundGraphError(`Graph.${name}: source node "${source}" not found.`);

  if (!targetData)
    throw new NotFoundGraphError(`Graph.${name}: target node "${target}" not found.`);

  // Must the graph generate an id for this edge?
  const eventData = {
    key: null,
    undirected,
    source,
    target,
    attributes
  };

  if (mustGenerateKey)
    edge = graph._edgeKeyGenerator(eventData);

  // Coercion of edge key
  edge = '' + edge;

  // Here, we have a key collision
  if (graph._edges.has(edge))
    throw new UsageGraphError(`Graph.${name}: the "${edge}" edge already exists in the graph.`);

  // Here, we might have a source / target collision
  if (
    !graph.multi &&
    (
      undirected ?
        typeof sourceData.undirected[target] !== 'undefined' :
        typeof sourceData.out[target] !== 'undefined'
    )
  ) {
    throw new UsageGraphError(`Graph.${name}: an edge linking "${source}" to "${target}" already exists. If you really want to add multiple edges linking those nodes, you should create a multi graph by using the 'multi' option.`);
  }

  // Storing some data
  const DataClass = undirected ? UndirectedEdgeData : DirectedEdgeData;

  const edgeData = new DataClass(
    edge,
    mustGenerateKey,
    sourceData,
    targetData,
    attributes
  );

  // Adding the edge to the internal register
  graph._edges.set(edge, edgeData);

  // Incrementing node degree counters
  if (source === target) {
    if (undirected)
      sourceData.undirectedSelfLoops++;
    else
      sourceData.directedSelfLoops++;
  }
  else {
    if (undirected) {
      sourceData.undirectedDegree++;
      targetData.undirectedDegree++;
    }
    else {
      sourceData.outDegree++;
      targetData.inDegree++;
    }
  }

  // Updating relevant index
  updateStructureIndex(
    graph,
    undirected,
    edgeData,
    source,
    target,
    sourceData,
    targetData
  );

  if (undirected)
    graph._undirectedSize++;
  else
    graph._directedSize++;

  // Emitting
  eventData.key = edge;

  graph.emit('edgeAdded', eventData);

  return edge;
}
function addEdge(
  graph,
  name,
  mustGenerateKey,
  undirected,
  edge,
  source,
  target,
  attributes
) {

  // Checking validity of operation
  if (!undirected && graph.type === 'undirected')
    throw new UsageGraphError(`Graph.${name}: you cannot add a directed edge to an undirected graph. Use the #.addEdge or #.addUndirectedEdge instead.`);

  if (undirected && graph.type === 'directed')
    throw new UsageGraphError(`Graph.${name}: you cannot add an undirected edge to a directed graph. Use the #.addEdge or #.addDirectedEdge instead.`);

  if (attributes && !isPlainObject(attributes))
    throw new InvalidArgumentsGraphError(`Graph.${name}: invalid attributes. Expecting an object but got "${attributes}"`);

  // Coercion of source & target:
  source = '' + source;
  target = '' + target;
  attributes = attributes || {};

  if (!graph.allowSelfLoops && source === target)
    throw new UsageGraphError(`Graph.${name}: source & target are the same ("${source}"), thus creating a loop explicitly forbidden by this graph 'allowSelfLoops' option set to false.`);

  const sourceData = graph._nodes.get(source),
        targetData = graph._nodes.get(target);

  if (!sourceData)
    throw new NotFoundGraphError(`Graph.${name}: source node "${source}" not found.`);

  if (!targetData)
    throw new NotFoundGraphError(`Graph.${name}: target node "${target}" not found.`);

  // Must the graph generate an id for this edge?
  const eventData = {
    key: null,
    undirected,
    source,
    target,
    attributes
  };

  if (mustGenerateKey)
    edge = graph._edgeKeyGenerator(eventData);

  // Coercion of edge key
  edge = '' + edge;

  // Here, we have a key collision
  if (graph._edges.has(edge))
    throw new UsageGraphError(`Graph.${name}: the "${edge}" edge already exists in the graph.`);

  // Here, we might have a source / target collision
  if (
    !graph.multi &&
    (
      undirected ?
        typeof sourceData.undirected[target] !== 'undefined' :
        typeof sourceData.out[target] !== 'undefined'
    )
  ) {
    throw new UsageGraphError(`Graph.${name}: an edge linking "${source}" to "${target}" already exists. If you really want to add multiple edges linking those nodes, you should create a multi graph by using the 'multi' option.`);
  }

  // Storing some data
  const DataClass = undirected ? UndirectedEdgeData : DirectedEdgeData;

  const edgeData = new DataClass(
    edge,
    mustGenerateKey,
    sourceData,
    targetData,
    attributes
  );

  // Adding the edge to the internal register
  graph._edges.set(edge, edgeData);

  // Incrementing node degree counters
  if (source === target) {
    if (undirected)
      sourceData.undirectedSelfLoops++;
    else
      sourceData.directedSelfLoops++;
  }
  else {
    if (undirected) {
      sourceData.undirectedDegree++;
      targetData.undirectedDegree++;
    }
    else {
      sourceData.outDegree++;
      targetData.inDegree++;
    }
  }

  // Updating relevant index
  updateStructureIndex(
    graph,
    undirected,
    edgeData,
    source,
    target,
    sourceData,
    targetData
  );

  if (undirected)
    graph._undirectedSize++;
  else
    graph._directedSize++;

  // Emitting
  eventData.key = edge;

  graph.emit('edgeAdded', eventData);

  return edge;
}
function addEdge ( graph , name , mustGenerateKey , undirected , edge , source , target , attributes ) { // Checking validity of operation if ( ! undirected && graph . type === 'undirected' ) throw new UsageGraphError ( ` ${ name } ` ) ; if ( undirected && graph . type === 'directed' ) throw new UsageGraphError ( ` ${ name } ` ) ; if ( attributes && ! isPlainObject ( attributes ) ) throw new InvalidArgumentsGraphError ( ` ${ name } ${ attributes } ` ) ; // Coercion of source & target: source = '' + source ; target = '' + target ; attributes = attributes || { } ; if ( ! graph . allowSelfLoops && source === target ) throw new UsageGraphError ( ` ${ name } ${ source } ` ) ; const sourceData = graph . _nodes . get ( source ) , targetData = graph . _nodes . get ( target ) ; if ( ! sourceData ) throw new NotFoundGraphError ( ` ${ name } ${ source } ` ) ; if ( ! targetData ) throw new NotFoundGraphError ( ` ${ name } ${ target } ` ) ; // Must the graph generate an id for this edge? const eventData = { key : null , undirected , source , target , attributes } ; if ( mustGenerateKey ) edge = graph . _edgeKeyGenerator ( eventData ) ; // Coercion of edge key edge = '' + edge ; // Here, we have a key collision if ( graph . _edges . has ( edge ) ) throw new UsageGraphError ( ` ${ name } ${ edge } ` ) ; // Here, we might have a source / target collision if ( ! graph . multi && ( undirected ? typeof sourceData . undirected [ target ] !== 'undefined' : typeof sourceData . out [ target ] !== 'undefined' ) ) { throw new UsageGraphError ( ` ${ name } ${ source } ${ target } ` ) ; } // Storing some data const DataClass = undirected ? UndirectedEdgeData : DirectedEdgeData ; const edgeData = new DataClass ( edge , mustGenerateKey , sourceData , targetData , attributes ) ; // Adding the edge to the internal register graph . _edges . set ( edge , edgeData ) ; // Incrementing node degree counters if ( source === target ) { if ( undirected ) sourceData . undirectedSelfLoops ++ ; else sourceData . directedSelfLoops ++ ; } else { if ( undirected ) { sourceData . undirectedDegree ++ ; targetData . undirectedDegree ++ ; } else { sourceData . outDegree ++ ; targetData . inDegree ++ ; } } // Updating relevant index updateStructureIndex ( graph , undirected , edgeData , source , target , sourceData , targetData ) ; if ( undirected ) graph . _undirectedSize ++ ; else graph . _directedSize ++ ; // Emitting eventData . key = edge ; graph . emit ( 'edgeAdded' , eventData ) ; return edge ; }
Abstract functions used by the Graph class for various methods.
 
Internal method used to add an arbitrary edge to the given graph.

@param  {Graph}   graph           - Target graph.
@param  {string}  name            - Name of the child method for errors.
@param  {boolean} mustGenerateKey - Should the graph generate an id?
@param  {boolean} undirected      - Whether the edge is undirected.
@param  {any}     edge            - The edge's key.
@param  {any}     source          - The source node.
@param  {any}     target          - The target node.
@param  {object}  [attributes]    - Optional attributes.
@return {any}                     - The edge.

@throws {Error} - Will throw if the graph is of the wrong type.
@throws {Error} - Will throw if the given attributes are not an object.
@throws {Error} - Will throw if source or target doesn't exist.
@throws {Error} - Will throw if the edge already exist.
Abstract functions used by the Graph class for various methods . Internal method used to add an arbitrary edge to the given graph .