function build(options) {
  YAML.defaultOptions.keepCstNodes = true;

  // Get input definition and prepare the specification's skeleton
  const definition = options.swaggerDefinition || options.definition;
  const specification = prepare(definition);
  const yamlDocsAnchors = new Map();
  const yamlDocsErrors = [];
  const yamlDocsReady = [];

  for (const filePath of convertGlobPaths(options.apis)) {
    try {
      const {
        yaml: yamlAnnotations,
        jsdoc: jsdocAnnotations,
      } = extractAnnotations(filePath, options.encoding);

      if (yamlAnnotations.length) {
        for (const annotation of yamlAnnotations) {
          const parsed = Object.assign(YAML.parseDocument(annotation), {
            filePath,
          });

          const anchors = parsed.anchors.getNames();
          if (anchors.length) {
            for (const anchor of anchors) {
              yamlDocsAnchors.set(anchor, parsed);
            }
          } else if (parsed.errors && parsed.errors.length) {
            // Attach the relevent yaml section to the error for verbose logging
            parsed.errors.forEach((err) => {
              err.annotation = annotation;
            });
            yamlDocsErrors.push(parsed);
          } else {
            yamlDocsReady.push(parsed);
          }
        }
      }

      if (jsdocAnnotations.length) {
        for (const annotation of jsdocAnnotations) {
          const jsDocComment = doctrine.parse(annotation, { unwrap: true });
          for (const doc of extractYamlFromJsDoc(jsDocComment)) {
            const parsed = Object.assign(YAML.parseDocument(doc), { filePath });

            const anchors = parsed.anchors.getNames();
            if (anchors.length) {
              for (const anchor of anchors) {
                yamlDocsAnchors.set(anchor, parsed);
              }
            } else if (parsed.errors && parsed.errors.length) {
              // Attach the relevent yaml section to the error for verbose logging
              parsed.errors.forEach((err) => {
                err.annotation = doc;
              });
              yamlDocsErrors.push(parsed);
            } else {
              yamlDocsReady.push(parsed);
            }
          }
        }
      }
    } catch (err) {
      if (options.failOnErrors) {
        console.error(`Error parsing ${filePath}: ${err.message}`);
        throw new Error(err);
      }
    }
  }

  if (yamlDocsErrors.length) {
    for (const docWithErr of yamlDocsErrors) {
      const errsToDelete = [];
      docWithErr.errors.forEach((error, index) => {
        if (error.name === 'YAMLReferenceError') {
          // This should either be a smart regex or ideally a YAML library method using the error.range.
          // The following works with both pretty and not pretty errors.
          const refErr = error.message
            .split('Aliased anchor not found: ')
            .filter((a) => a)
            .join('')
            .split(' at line')[0];
          const anchor = yamlDocsAnchors.get(refErr);
          const anchorString = anchor.cstNode.toString();
          const originalString = docWithErr.cstNode.toString();
          const readyDocument = YAML.parseDocument(
            `${anchorString}\n${originalString}`
          );

          yamlDocsReady.push(readyDocument);
          errsToDelete.push(index);
        }
      });
      // reverse sort the deletion array so we always delete from the end
      errsToDelete.sort((a, b) => b - a);

      // Cleanup solved errors in order to allow for parser to pass through.
      for (const errIndex of errsToDelete) {
        docWithErr.errors.splice(errIndex, 1);
      }
    }

    // Format errors into a printable/throwable string
    const errReport = yamlDocsErrors
      .filter((doc) => doc.errors.length)
      .map(({ errors, filePath }) => {
        let str = `Error in ${filePath} :\n`;
        if (options.verbose) {
          str += errors
            .map(
              (e) =>
                `${e.toString()}\nImbedded within:\n\`\`\`\n  ${e.annotation.replace(
                  /\n/g,
                  '\n  '
                )}\n\`\`\``
            )
            .join('\n');
        } else {
          str += errors.map((e) => e.toString()).join('\n');
        }
        return str;
      })
      .filter((error) => !!error);

    if (errReport.length) {
      if (options.failOnErrors) {
        throw new Error(errReport);
      }
      // Place to provide feedback for errors. Previously throwing, now reporting only.
      console.info(
        'Not all input has been taken into account at your final specification.'
      );

      console.error(`Here's the report: \n\n\n ${errReport}`);
    }
  }

  for (const document of yamlDocsReady) {
    const parsedDoc = document.toJSON();
    for (const property in parsedDoc) {
      organize(specification, parsedDoc, property);
    }
  }

  return finalize(specification, options);
}
@param {object} options
@returns {object} swaggerObject