public static invoke()

in apps/api-extractor/src/api/Extractor.ts [191:430]


  public static invoke(extractorConfig: ExtractorConfig, options?: IExtractorInvokeOptions): ExtractorResult {
    if (!options) {
      options = {};
    }

    const localBuild: boolean = options.localBuild || false;

    let compilerState: CompilerState | undefined;
    if (options.compilerState) {
      compilerState = options.compilerState;
    } else {
      compilerState = CompilerState.create(extractorConfig, options);
    }

    const messageRouter: MessageRouter = new MessageRouter({
      workingPackageFolder: extractorConfig.packageFolder,
      messageCallback: options.messageCallback,
      messagesConfig: extractorConfig.messages || {},
      showVerboseMessages: !!options.showVerboseMessages,
      showDiagnostics: !!options.showDiagnostics,
      tsdocConfiguration: extractorConfig.tsdocConfiguration
    });

    if (extractorConfig.tsdocConfigFile.filePath && !extractorConfig.tsdocConfigFile.fileNotFound) {
      if (!Path.isEqual(extractorConfig.tsdocConfigFile.filePath, ExtractorConfig._tsdocBaseFilePath)) {
        messageRouter.logVerbose(
          ConsoleMessageId.UsingCustomTSDocConfig,
          'Using custom TSDoc config from ' + extractorConfig.tsdocConfigFile.filePath
        );
      }
    }

    this._checkCompilerCompatibility(extractorConfig, messageRouter);

    if (messageRouter.showDiagnostics) {
      messageRouter.logDiagnostic('');
      messageRouter.logDiagnosticHeader('Final prepared ExtractorConfig');
      messageRouter.logDiagnostic(extractorConfig.getDiagnosticDump());
      messageRouter.logDiagnosticFooter();

      messageRouter.logDiagnosticHeader('Compiler options');
      const serializedCompilerOptions: object = MessageRouter.buildJsonDumpObject(
        (compilerState.program as ts.Program).getCompilerOptions()
      );
      messageRouter.logDiagnostic(JSON.stringify(serializedCompilerOptions, undefined, 2));
      messageRouter.logDiagnosticFooter();

      messageRouter.logDiagnosticHeader('TSDoc configuration');
      // Convert the TSDocConfiguration into a tsdoc.json representation
      const combinedConfigFile: TSDocConfigFile = TSDocConfigFile.loadFromParser(
        extractorConfig.tsdocConfiguration
      );
      const serializedTSDocConfig: object = MessageRouter.buildJsonDumpObject(
        combinedConfigFile.saveToObject()
      );
      messageRouter.logDiagnostic(JSON.stringify(serializedTSDocConfig, undefined, 2));
      messageRouter.logDiagnosticFooter();
    }

    const collector: Collector = new Collector({
      program: compilerState.program as ts.Program,
      messageRouter,
      extractorConfig: extractorConfig
    });

    collector.analyze();

    DocCommentEnhancer.analyze(collector);
    ValidationEnhancer.analyze(collector);

    const modelBuilder: ApiModelGenerator = new ApiModelGenerator(collector);
    const apiPackage: ApiPackage = modelBuilder.buildApiPackage();

    if (messageRouter.showDiagnostics) {
      messageRouter.logDiagnostic(''); // skip a line after any diagnostic messages
    }

    if (extractorConfig.docModelEnabled) {
      messageRouter.logVerbose(
        ConsoleMessageId.WritingDocModelFile,
        'Writing: ' + extractorConfig.apiJsonFilePath
      );
      apiPackage.saveToJsonFile(extractorConfig.apiJsonFilePath, {
        toolPackage: Extractor.packageName,
        toolVersion: Extractor.version,

        newlineConversion: extractorConfig.newlineKind,
        ensureFolderExists: true,
        testMode: extractorConfig.testMode
      });
    }

    let apiReportChanged: boolean = false;

    if (extractorConfig.apiReportEnabled) {
      const actualApiReportPath: string = extractorConfig.reportTempFilePath;
      const actualApiReportShortPath: string = extractorConfig._getShortFilePath(
        extractorConfig.reportTempFilePath
      );

      const expectedApiReportPath: string = extractorConfig.reportFilePath;
      const expectedApiReportShortPath: string = extractorConfig._getShortFilePath(
        extractorConfig.reportFilePath
      );

      const actualApiReportContent: string = ApiReportGenerator.generateReviewFileContent(collector);

      // Write the actual file
      FileSystem.writeFile(actualApiReportPath, actualApiReportContent, {
        ensureFolderExists: true,
        convertLineEndings: extractorConfig.newlineKind
      });

      // Compare it against the expected file
      if (FileSystem.exists(expectedApiReportPath)) {
        const expectedApiReportContent: string = FileSystem.readFile(expectedApiReportPath);

        if (
          !ApiReportGenerator.areEquivalentApiFileContents(actualApiReportContent, expectedApiReportContent)
        ) {
          apiReportChanged = true;

          if (!localBuild) {
            // For a production build, issue a warning that will break the CI build.
            messageRouter.logWarning(
              ConsoleMessageId.ApiReportNotCopied,
              'You have changed the public API signature for this project.' +
                ` Please copy the file "${actualApiReportShortPath}" to "${expectedApiReportShortPath}",` +
                ` or perform a local build (which does this automatically).` +
                ` See the Git repo documentation for more info.`
            );
          } else {
            // For a local build, just copy the file automatically.
            messageRouter.logWarning(
              ConsoleMessageId.ApiReportCopied,
              'You have changed the public API signature for this project.' +
                ` Updating ${expectedApiReportShortPath}`
            );

            FileSystem.writeFile(expectedApiReportPath, actualApiReportContent, {
              ensureFolderExists: true,
              convertLineEndings: extractorConfig.newlineKind
            });
          }
        } else {
          messageRouter.logVerbose(
            ConsoleMessageId.ApiReportUnchanged,
            `The API report is up to date: ${actualApiReportShortPath}`
          );
        }
      } else {
        // The target file does not exist, so we are setting up the API review file for the first time.
        //
        // NOTE: People sometimes make a mistake where they move a project and forget to update the "reportFolder"
        // setting, which causes a new file to silently get written to the wrong place.  This can be confusing.
        // Thus we treat the initial creation of the file specially.
        apiReportChanged = true;

        if (!localBuild) {
          // For a production build, issue a warning that will break the CI build.
          messageRouter.logWarning(
            ConsoleMessageId.ApiReportNotCopied,
            'The API report file is missing.' +
              ` Please copy the file "${actualApiReportShortPath}" to "${expectedApiReportShortPath}",` +
              ` or perform a local build (which does this automatically).` +
              ` See the Git repo documentation for more info.`
          );
        } else {
          const expectedApiReportFolder: string = path.dirname(expectedApiReportPath);
          if (!FileSystem.exists(expectedApiReportFolder)) {
            messageRouter.logError(
              ConsoleMessageId.ApiReportFolderMissing,
              'Unable to create the API report file. Please make sure the target folder exists:\n' +
                expectedApiReportFolder
            );
          } else {
            FileSystem.writeFile(expectedApiReportPath, actualApiReportContent, {
              convertLineEndings: extractorConfig.newlineKind
            });
            messageRouter.logWarning(
              ConsoleMessageId.ApiReportCreated,
              'The API report file was missing, so a new file was created. Please add this file to Git:\n' +
                expectedApiReportPath
            );
          }
        }
      }
    }

    if (extractorConfig.rollupEnabled) {
      Extractor._generateRollupDtsFile(
        collector,
        extractorConfig.publicTrimmedFilePath,
        DtsRollupKind.PublicRelease,
        extractorConfig.newlineKind
      );
      Extractor._generateRollupDtsFile(
        collector,
        extractorConfig.betaTrimmedFilePath,
        DtsRollupKind.BetaRelease,
        extractorConfig.newlineKind
      );
      Extractor._generateRollupDtsFile(
        collector,
        extractorConfig.untrimmedFilePath,
        DtsRollupKind.InternalRelease,
        extractorConfig.newlineKind
      );
    }

    if (extractorConfig.tsdocMetadataEnabled) {
      // Write the tsdoc-metadata.json file for this project
      PackageMetadataManager.writeTsdocMetadataFile(
        extractorConfig.tsdocMetadataFilePath,
        extractorConfig.newlineKind
      );
    }

    // Show all the messages that we collected during analysis
    messageRouter.handleRemainingNonConsoleMessages();

    // Determine success
    let succeeded: boolean;
    if (localBuild) {
      // For a local build, fail if there were errors (but ignore warnings)
      succeeded = messageRouter.errorCount === 0;
    } else {
      // For a production build, fail if there were any errors or warnings
      succeeded = messageRouter.errorCount + messageRouter.warningCount === 0;
    }

    return new ExtractorResult({
      compilerState,
      extractorConfig,
      succeeded,
      apiReportChanged,
      errorCount: messageRouter.errorCount,
      warningCount: messageRouter.warningCount
    });
  }