src/graph.js
function traceFromNode(name) {
    const job = {
      node: name,
      isValid: true
    };

    invalidatePendingJobsForNode(pendingJobs, name);

    // Ensure the job can be tracked
    pendingJobs.push(job);

    // Force an asynchronous start to the tracing so that other parts of a
    // codebase can synchronously trigger the job to be invalidated. This
    // helps to avoid any unnecessary work that may no longer be relevant
    process.nextTick(startTracingNode);

    if (!hasSignalledStart) {
      hasSignalledStart = true;
      events.emit('started', {state: state});
    }

    function startTracingNode() {
      // Handle situations where a job may have been invalidated further
      // down the stack from where the original call originated from
      if (!job.isValid) {
        return;
      }

      getDependencies(name)
        .then(handleDependencies)
        .catch(handleError)
        .then(signalIfCompleted);

      function handleDependencies(dependencies) {
        // If this job has been invalidated, we can ignore anything that may
        // have resulted from it
        if (!job.isValid) {
          return;
        }

        // Indicate that this job is no longer blocking the `completed` stage
        pull(pendingJobs, job);

        // Sanity check
        if (!isArray(dependencies)) {
          return Promise.reject(
            new Error(`Dependencies should be specified in an array. Received ${dependencies}`)
          );
        }

        const previousState = state;

        if (!isNodeDefined(state, name)) {
          state = addNode(state, name);
        }

        // If there are any dependencies encountered that we don't already
        // know about, we start tracing them
        dependencies.forEach(depName => {
          if (
            !isNodeDefined(state, depName) &&
            !isNodePending(pendingJobs, depName)
          ) {
            traceFromNode(depName);
          }

          if (!isNodeDefined(state, depName)) {
            state = addNode(state, depName);
          }

          state = addEdge(state, name, depName);
        });

        // Enable progress updates
        events.emit('traced', {
          node: name,
          diff: Diff({
            from: previousState,
            to: state
          })
        });
      }

      function handleError(err) {
        // Indicate that this job is no longer blocking the `completed` stage
        pull(pendingJobs, job);

        // If the job has been invalidated, we ignore the error
        if (!job.isValid) {
          return;
        }

        const signal = {
          error: err,
          node: name,
          state: state
        };

        errors.push(signal);
        events.emit('error', signal);
      }
    }
  }
function traceFromNode(name) {
    const job = {
      node: name,
      isValid: true
    };

    invalidatePendingJobsForNode(pendingJobs, name);

    // Ensure the job can be tracked
    pendingJobs.push(job);

    // Force an asynchronous start to the tracing so that other parts of a
    // codebase can synchronously trigger the job to be invalidated. This
    // helps to avoid any unnecessary work that may no longer be relevant
    process.nextTick(startTracingNode);

    if (!hasSignalledStart) {
      hasSignalledStart = true;
      events.emit('started', {state: state});
    }

    function startTracingNode() {
      // Handle situations where a job may have been invalidated further
      // down the stack from where the original call originated from
      if (!job.isValid) {
        return;
      }

      getDependencies(name)
        .then(handleDependencies)
        .catch(handleError)
        .then(signalIfCompleted);

      function handleDependencies(dependencies) {
        // If this job has been invalidated, we can ignore anything that may
        // have resulted from it
        if (!job.isValid) {
          return;
        }

        // Indicate that this job is no longer blocking the `completed` stage
        pull(pendingJobs, job);

        // Sanity check
        if (!isArray(dependencies)) {
          return Promise.reject(
            new Error(`Dependencies should be specified in an array. Received ${dependencies}`)
          );
        }

        const previousState = state;

        if (!isNodeDefined(state, name)) {
          state = addNode(state, name);
        }

        // If there are any dependencies encountered that we don't already
        // know about, we start tracing them
        dependencies.forEach(depName => {
          if (
            !isNodeDefined(state, depName) &&
            !isNodePending(pendingJobs, depName)
          ) {
            traceFromNode(depName);
          }

          if (!isNodeDefined(state, depName)) {
            state = addNode(state, depName);
          }

          state = addEdge(state, name, depName);
        });

        // Enable progress updates
        events.emit('traced', {
          node: name,
          diff: Diff({
            from: previousState,
            to: state
          })
        });
      }

      function handleError(err) {
        // Indicate that this job is no longer blocking the `completed` stage
        pull(pendingJobs, job);

        // If the job has been invalidated, we ignore the error
        if (!job.isValid) {
          return;
        }

        const signal = {
          error: err,
          node: name,
          state: state
        };

        errors.push(signal);
        events.emit('error', signal);
      }
    }
  }
function traceFromNode ( name ) { const job = { node : name , isValid : true } ; invalidatePendingJobsForNode ( pendingJobs , name ) ; // Ensure the job can be tracked pendingJobs . push ( job ) ; // Force an asynchronous start to the tracing so that other parts of a // codebase can synchronously trigger the job to be invalidated. This // helps to avoid any unnecessary work that may no longer be relevant process . nextTick ( startTracingNode ) ; if ( ! hasSignalledStart ) { hasSignalledStart = true ; events . emit ( 'started' , { state : state } ) ; } function startTracingNode ( ) { // Handle situations where a job may have been invalidated further // down the stack from where the original call originated from if ( ! job . isValid ) { return ; } getDependencies ( name ) . then ( handleDependencies ) . catch ( handleError ) . then ( signalIfCompleted ) ; function handleDependencies ( dependencies ) { // If this job has been invalidated, we can ignore anything that may // have resulted from it if ( ! job . isValid ) { return ; } // Indicate that this job is no longer blocking the `completed` stage pull ( pendingJobs , job ) ; // Sanity check if ( ! isArray ( dependencies ) ) { return Promise . reject ( new Error ( ` ${ dependencies } ` ) ) ; } const previousState = state ; if ( ! isNodeDefined ( state , name ) ) { state = addNode ( state , name ) ; } // If there are any dependencies encountered that we don't already // know about, we start tracing them dependencies . forEach ( depName => { if ( ! isNodeDefined ( state , depName ) && ! isNodePending ( pendingJobs , depName ) ) { traceFromNode ( depName ) ; } if ( ! isNodeDefined ( state , depName ) ) { state = addNode ( state , depName ) ; } state = addEdge ( state , name , depName ) ; } ) ; // Enable progress updates events . emit ( 'traced' , { node : name , diff : Diff ( { from : previousState , to : state } ) } ) ; } function handleError ( err ) { // Indicate that this job is no longer blocking the `completed` stage pull ( pendingJobs , job ) ; // If the job has been invalidated, we ignore the error if ( ! job . isValid ) { return ; } const signal = { error : err , node : name , state : state } ; errors . push ( signal ) ; events . emit ( 'error' , signal ) ; } } }
Invoke the specified `getDependencies` function and build the
graph by recursively traversing unknown nodes

@param {String} name
Invoke the specified getDependencies function and build the graph by recursively traversing unknown nodes