async function resolveAuditsToDefns(audits, configDir) {
  if (!audits) {
    return null;
  }

  const coreList = Runner.getAuditList();
  const auditDefnsPromises = audits.map(async (auditJson) => {
    const auditDefn = expandAuditShorthand(auditJson);
    let implementation;
    if ('implementation' in auditDefn) {
      implementation = auditDefn.implementation;
    } else {
      implementation = await requireAudit(auditDefn.path, coreList, configDir);
    }

    return {
      implementation,
      path: auditDefn.path,
      options: auditDefn.options || {},
    };
  });
  const auditDefns = await Promise.all(auditDefnsPromises);

  const mergedAuditDefns = mergeOptionsOfItems(auditDefns);
  mergedAuditDefns.forEach(audit => validation.assertValidAudit(audit));
  return mergedAuditDefns;
}
Take an array of audits and audit paths and require any paths (possibly
relative to the optional `configDir`) using `resolveModule`,
leaving only an array of AuditDefns.
@param {LH.Config['audits']} audits
@param {string=} configDir
@return {Promise<Array<LH.Config.AuditDefn>|null>}