Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 22 additions & 22 deletions heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,18 @@ export interface IApiExtractorTaskConfiguration {
}

export default class ApiExtractorPlugin implements IHeftTaskPlugin {
private _apiExtractor: typeof TApiExtractor | undefined;
private _apiExtractorConfigurationFilePath: string | undefined | typeof UNINITIALIZED = UNINITIALIZED;
private _printedWatchWarning: boolean = false;
#apiExtractor: typeof TApiExtractor | undefined;
#apiExtractorConfigurationFilePath: string | undefined | typeof UNINITIALIZED = UNINITIALIZED;
#printedWatchWarning: boolean = false;

public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void {
const runAsync = async (
runOptions: IHeftTaskRunHookOptions & Partial<IHeftTaskRunIncrementalHookOptions>
): Promise<void> => {
const result: IApiExtractorConfigurationResult | undefined =
await this._getApiExtractorConfigurationAsync(taskSession, heftConfiguration);
await this.#getApiExtractorConfigurationAsync(taskSession, heftConfiguration);
if (result) {
await this._runApiExtractorAsync(
await this.#runApiExtractorAsync(
taskSession,
heftConfiguration,
runOptions,
Expand All @@ -88,19 +88,19 @@ export default class ApiExtractorPlugin implements IHeftTaskPlugin {
taskSession.hooks.runIncremental.tapPromise(PLUGIN_NAME, runAsync);
}

private async _getApiExtractorConfigurationFilePathAsync(
async #getApiExtractorConfigurationFilePathAsync(
taskSession: IHeftTaskSession,
heftConfiguration: HeftConfiguration
): Promise<string | undefined> {
if (this._apiExtractorConfigurationFilePath === UNINITIALIZED) {
this._apiExtractorConfigurationFilePath =
if (this.#apiExtractorConfigurationFilePath === UNINITIALIZED) {
this.#apiExtractorConfigurationFilePath =
await heftConfiguration.rigConfig.tryResolveConfigFilePathAsync(EXTRACTOR_CONFIG_RELATIVE_PATH);
if (this._apiExtractorConfigurationFilePath === undefined) {
this._apiExtractorConfigurationFilePath =
if (this.#apiExtractorConfigurationFilePath === undefined) {
this.#apiExtractorConfigurationFilePath =
await heftConfiguration.rigConfig.tryResolveConfigFilePathAsync(
LEGACY_EXTRACTOR_CONFIG_RELATIVE_PATH
);
if (this._apiExtractorConfigurationFilePath !== undefined) {
if (this.#apiExtractorConfigurationFilePath !== undefined) {
taskSession.logger.emitWarning(
new Error(
`The "${LEGACY_EXTRACTOR_CONFIG_RELATIVE_PATH}" configuration file path is not supported ` +
Expand All @@ -110,10 +110,10 @@ export default class ApiExtractorPlugin implements IHeftTaskPlugin {
}
}
}
return this._apiExtractorConfigurationFilePath;
return this.#apiExtractorConfigurationFilePath;
}

private async _getApiExtractorConfigurationAsync(
async #getApiExtractorConfigurationAsync(
taskSession: IHeftTaskSession,
heftConfiguration: HeftConfiguration,
ignoreMissingEntryPoint?: boolean
Expand All @@ -122,14 +122,14 @@ export default class ApiExtractorPlugin implements IHeftTaskPlugin {
// including support for rig.json. However, Heft does not load the @microsoft/api-extractor package at all
// unless it sees a config/api-extractor.json file. Thus we need to do our own lookup here.
const apiExtractorConfigurationFilePath: string | undefined =
await this._getApiExtractorConfigurationFilePathAsync(taskSession, heftConfiguration);
await this.#getApiExtractorConfigurationFilePathAsync(taskSession, heftConfiguration);
if (!apiExtractorConfigurationFilePath) {
return undefined;
}

// Since the config file exists, we can assume that API Extractor is available. Attempt to resolve
// and import the package. If the resolution fails, a helpful error is thrown.
const apiExtractorPackage: typeof TApiExtractor = await this._getApiExtractorPackageAsync(
const apiExtractorPackage: typeof TApiExtractor = await this.#getApiExtractorPackageAsync(
taskSession,
heftConfiguration
);
Expand All @@ -149,21 +149,21 @@ export default class ApiExtractorPlugin implements IHeftTaskPlugin {
return { apiExtractorPackage, apiExtractorConfiguration };
}

private async _getApiExtractorPackageAsync(
async #getApiExtractorPackageAsync(
taskSession: IHeftTaskSession,
heftConfiguration: HeftConfiguration
): Promise<typeof TApiExtractor> {
if (!this._apiExtractor) {
if (!this.#apiExtractor) {
const apiExtractorPackagePath: string = await heftConfiguration.rigPackageResolver.resolvePackageAsync(
'@microsoft/api-extractor',
taskSession.logger.terminal
);
this._apiExtractor = (await import(apiExtractorPackagePath)) as typeof TApiExtractor;
this.#apiExtractor = (await import(apiExtractorPackagePath)) as typeof TApiExtractor;
}
return this._apiExtractor;
return this.#apiExtractor;
}

private async _runApiExtractorAsync(
async #runApiExtractorAsync(
taskSession: IHeftTaskSession,
heftConfiguration: HeftConfiguration,
runOptions: IHeftTaskRunHookOptions & Partial<IHeftTaskRunIncrementalHookOptions>,
Expand All @@ -181,8 +181,8 @@ export default class ApiExtractorPlugin implements IHeftTaskPlugin {

if (runOptions.requestRun) {
if (!runInWatchMode) {
if (!this._printedWatchWarning) {
this._printedWatchWarning = true;
if (!this.#printedWatchWarning) {
this.#printedWatchWarning = true;
taskSession.logger.terminal.writeWarningLine(
"API Extractor isn't currently enabled in watch mode."
);
Expand Down
90 changes: 45 additions & 45 deletions heft-plugins/heft-jest-plugin/src/HeftJestReporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,21 @@ export interface IHeftJestReporterOptions {
* https://github.com/facebook/jest/blob/main/packages/jest-reporters/src/default_reporter.ts
*/
export default class HeftJestReporter implements Reporter {
private _terminal: ITerminal;
private _buildFolderPath: string;
private _debugMode: boolean;
#terminal: ITerminal;
#buildFolderPath: string;
#debugMode: boolean;

public constructor(jestConfig: Config.GlobalConfig, options: IHeftJestReporterOptions) {
this._terminal = options.logger.terminal;
this._buildFolderPath = options.heftConfiguration.buildFolderPath;
this._debugMode = options.debugMode;
this.#terminal = options.logger.terminal;
this.#buildFolderPath = options.heftConfiguration.buildFolderPath;
this.#debugMode = options.debugMode;
}

// eslint-disable-next-line @typescript-eslint/naming-convention
public async onTestStart(test: Test): Promise<void> {
this._terminal.writeLine(
this.#terminal.writeLine(
Colorize.whiteBackground(Colorize.black('START')),
` ${this._getTestPath(test.path)}`
` ${this.#getTestPath(test.path)}`
);
}

Expand All @@ -59,7 +59,7 @@ export default class HeftJestReporter implements Reporter {
testResult: TestResult,
aggregatedResult: AggregatedResult
): Promise<void> {
this._writeConsoleOutput(testResult);
this.#writeConsoleOutput(testResult);
const {
numPassingTests,
numFailingTests,
Expand All @@ -80,39 +80,39 @@ export default class HeftJestReporter implements Reporter {
const memUsage: string = memoryUsage ? `, ${Math.floor(memoryUsage / 1000000)}MB heap size` : '';

const message: string =
` ${this._getTestPath(test.path)} ` +
` ${this.#getTestPath(test.path)} ` +
`(duration: ${duration}, ${numPassingTests} passed, ${numFailingTests} failed${memUsage})`;

if (numFailingTests > 0) {
this._terminal.writeLine(Colorize.redBackground(Colorize.black('FAIL')), message);
this.#terminal.writeLine(Colorize.redBackground(Colorize.black('FAIL')), message);
} else if (testExecError) {
this._terminal.writeLine(
this.#terminal.writeLine(
Colorize.redBackground(Colorize.black(`FAIL (${testExecError.type})`)),
message
);
} else {
this._terminal.writeLine(Colorize.greenBackground(Colorize.black('PASS')), message);
this.#terminal.writeLine(Colorize.greenBackground(Colorize.black('PASS')), message);
}

if (failureMessage) {
this._terminal.writeErrorLine(failureMessage);
this.#terminal.writeErrorLine(failureMessage);
}

if (updatedSnapshots) {
this._terminal.writeErrorLine(
`Updated ${this._formatWithPlural(updatedSnapshots, 'snapshot', 'snapshots')}`
this.#terminal.writeErrorLine(
`Updated ${this.#formatWithPlural(updatedSnapshots, 'snapshot', 'snapshots')}`
);
}

if (addedSnapshots) {
this._terminal.writeErrorLine(
`Added ${this._formatWithPlural(addedSnapshots, 'snapshot', 'snapshots')}`
this.#terminal.writeErrorLine(
`Added ${this.#formatWithPlural(addedSnapshots, 'snapshot', 'snapshots')}`
);
}

if (uncheckedSnapshots) {
this._terminal.writeWarningLine(
`${this._formatWithPlural(uncheckedSnapshots, 'snapshot was', 'snapshots were')} not checked`
this.#terminal.writeWarningLine(
`${this.#formatWithPlural(uncheckedSnapshots, 'snapshot was', 'snapshots were')} not checked`
);
}
}
Expand All @@ -122,30 +122,30 @@ export default class HeftJestReporter implements Reporter {
// a build failure and searching its log output for errors. To reduce confusion, we add a prefix
// like "|console.error|" to each output line, to clearly distinguish test logging from regular
// task output. You can suppress test logging entirely using the "--silent" CLI parameter.
private _writeConsoleOutput(testResult: TestResult): void {
#writeConsoleOutput(testResult: TestResult): void {
if (testResult.console) {
for (const logEntry of testResult.console) {
switch (logEntry.type) {
case 'debug':
this._writeConsoleOutputWithLabel('console.debug', logEntry.message);
this.#writeConsoleOutputWithLabel('console.debug', logEntry.message);
break;
case 'log':
this._writeConsoleOutputWithLabel('console.log', logEntry.message);
this.#writeConsoleOutputWithLabel('console.log', logEntry.message);
break;
case 'warn':
this._writeConsoleOutputWithLabel('console.warn', logEntry.message);
this.#writeConsoleOutputWithLabel('console.warn', logEntry.message);
break;
case 'error':
this._writeConsoleOutputWithLabel('console.error', logEntry.message);
this.#writeConsoleOutputWithLabel('console.error', logEntry.message);
break;
case 'info':
this._writeConsoleOutputWithLabel('console.info', logEntry.message);
this.#writeConsoleOutputWithLabel('console.info', logEntry.message);
break;

case 'groupCollapsed':
if (this._debugMode) {
if (this.#debugMode) {
// The "groupCollapsed" name is too long
this._writeConsoleOutputWithLabel('collapsed', logEntry.message);
this.#writeConsoleOutputWithLabel('collapsed', logEntry.message);
}
break;

Expand All @@ -155,8 +155,8 @@ export default class HeftJestReporter implements Reporter {
case 'dirxml':
case 'group':
case 'time':
if (this._debugMode) {
this._writeConsoleOutputWithLabel(
if (this.#debugMode) {
this.#writeConsoleOutputWithLabel(
logEntry.type,
`(${logEntry.type}) ${logEntry.message}`,
true
Expand All @@ -172,7 +172,7 @@ export default class HeftJestReporter implements Reporter {
}
}

private _writeConsoleOutputWithLabel(label: string, message: string, debug?: boolean): void {
#writeConsoleOutputWithLabel(label: string, message: string, debug?: boolean): void {
if (message === '') {
return;
}
Expand All @@ -185,7 +185,7 @@ export default class HeftJestReporter implements Reporter {
const prefix: string = debug ? Colorize.yellow(paddedLabel) : Colorize.cyan(paddedLabel);

for (const line of lines) {
this._terminal.writeLine(prefix, ' ' + line);
this.#terminal.writeLine(prefix, ' ' + line);
}
}

Expand All @@ -196,9 +196,9 @@ export default class HeftJestReporter implements Reporter {
): Promise<void> {
// Jest prints some text that changes the console's color without a newline, so we reset the console's color here
// and print a newline.
this._terminal.writeLine('\u001b[0m');
this._terminal.writeLine(
`Run start. ${this._formatWithPlural(aggregatedResult.numTotalTestSuites, 'test suite', 'test suites')}`
this.#terminal.writeLine('\u001b[0m');
this.#terminal.writeLine(
`Run start. ${this.#formatWithPlural(aggregatedResult.numTotalTestSuites, 'test suite', 'test suites')}`
);
}

Expand All @@ -212,37 +212,37 @@ export default class HeftJestReporter implements Reporter {
snapshot: { uncheckedKeysByFile: uncheckedSnapshotsByFile }
} = results;

this._terminal.writeLine();
this._terminal.writeLine('Tests finished:');
this.#terminal.writeLine();
this.#terminal.writeLine('Tests finished:');

const successesText: string = ` Successes: ${numPassedTests}`;
this._terminal.writeLine(numPassedTests > 0 ? Colorize.green(successesText) : successesText);
this.#terminal.writeLine(numPassedTests > 0 ? Colorize.green(successesText) : successesText);

const failText: string = ` Failures: ${numFailedTests}`;
this._terminal.writeLine(numFailedTests > 0 ? Colorize.red(failText) : failText);
this.#terminal.writeLine(numFailedTests > 0 ? Colorize.red(failText) : failText);

if (numRuntimeErrorTestSuites) {
this._terminal.writeLine(Colorize.red(` Failed test suites: ${numRuntimeErrorTestSuites}`));
this.#terminal.writeLine(Colorize.red(` Failed test suites: ${numRuntimeErrorTestSuites}`));
}

if (uncheckedSnapshotsByFile.length > 0) {
this._terminal.writeWarningLine(
this.#terminal.writeWarningLine(
` Test suites with unchecked snapshots: ${uncheckedSnapshotsByFile.length}`
);
}

this._terminal.writeLine(` Total: ${numTotalTests}`);
this.#terminal.writeLine(` Total: ${numTotalTests}`);
}

public getLastError(): void {
// This reporter doesn't have any errors to throw
}

private _getTestPath(fullTestPath: string): string {
return path.relative(this._buildFolderPath, fullTestPath);
#getTestPath(fullTestPath: string): string {
return path.relative(this.#buildFolderPath, fullTestPath);
}

private _formatWithPlural(num: number, singular: string, plural: string): string {
#formatWithPlural(num: number, singular: string, plural: string): string {
return `${num} ${num === 1 ? singular : plural}`;
}
}
Loading
Loading