function parse(moduleName, fileName, fileContents, options) {
  options = options || {};

  //Set up source input
  var i, moduleCall, depString,
      moduleDeps = [],
      result = '',
      moduleList = [],
      needsDefine = true,
      astRoot = esprima.parse(fileContents);

  parse.recurse(astRoot, function(callName, config, name, deps) {
    if (!deps) {
      deps = [];
    }

    if (callName === 'define' && (!name || name === moduleName)) {
      needsDefine = false;
    }

    if (!name) {
      //If there is no module name, the dependencies are for
      //this file/default module name.
      moduleDeps = moduleDeps.concat(deps);
    } else {
      moduleList.push({
        name: name,
        deps: deps
      });
    }

    //If define was found, no need to dive deeper, unless
    //the config explicitly wants to dig deeper.
    return !!options.findNestedDependencies;
  }, options);

  if (options.insertNeedsDefine && needsDefine) {
    result += 'require.needsDefine("' + moduleName + '");';
  }

  if (moduleDeps.length || moduleList.length) {
    for (i = 0; i < moduleList.length; i++) {
      moduleCall = moduleList[i];
      if (result) {
        result += '\n';
      }

      //If this is the main module for this file, combine any
      //"anonymous" dependencies (could come from a nested require
      //call) with this module.
      if (moduleCall.name === moduleName) {
        moduleCall.deps = moduleCall.deps.concat(moduleDeps);
        moduleDeps = [];
      }

      depString = arrayToString(moduleCall.deps);
      result += 'define("' + moduleCall.name + '",' +
          depString + ');';
    }
    if (moduleDeps.length) {
      if (result) {
        result += '\n';
      }
      depString = arrayToString(moduleDeps);
      result += 'define("' + moduleName + '",' + depString + ');';
    }
  }

  return result || null;
}
Main parse function. Returns a string of any valid require or
define/require.def calls as part of one JavaScript source string.
@param {String} moduleName the module name that represents this file.
It is used to create a default define if there is not one already for the
file. This allows properly tracing dependencies for builds. Otherwise, if
the file just has a require() call, the file dependencies will not be
properly reflected: the file will come before its dependencies.
@param {String} moduleName
@param {String} fileName
@param {String} fileContents
@param {Object} options optional options. insertNeedsDefine: true will
add calls to require.needsDefine() if appropriate.
@returns {String} JS source string or null, if no require or
define/require.def calls are found.