mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-11 09:03:29 +01:00
build: package api-extractor and -model (#9920)
* fix(ExceptText): don't display import("d..-types/v10"). in return type
* Squashed 'packages/api-extractor-model/' content from commit 39ecb196c
git-subtree-dir: packages/api-extractor-model
git-subtree-split: 39ecb196ca210bdf84ba6c9cadb1bb93571849d7
* Squashed 'packages/api-extractor/' content from commit 341ad6c51
git-subtree-dir: packages/api-extractor
git-subtree-split: 341ad6c51b01656d4f73b74ad4bdb3095f9262c4
* feat(api-extractor): add api-extractor and -model
* fix: package.json docs script
* fix(SourcLink): use <> instead of function syntax
* fix: make packages private
* fix: rest params showing in docs, added labels
* fix: missed two files
* fix: cpy-cli & pnpm-lock
* fix: increase icon size
* fix: icon size again
This commit is contained in:
201
packages/api-extractor/src/api/CompilerState.ts
Normal file
201
packages/api-extractor/src/api/CompilerState.ts
Normal file
@@ -0,0 +1,201 @@
|
||||
/* eslint-disable no-case-declarations */
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
import * as path from 'node:path';
|
||||
import { JsonFile } from '@rushstack/node-core-library';
|
||||
import colors from 'colors';
|
||||
import * as ts from 'typescript';
|
||||
import type { IExtractorInvokeOptions } from './Extractor.js';
|
||||
import { ExtractorConfig } from './ExtractorConfig.js';
|
||||
|
||||
/**
|
||||
* Options for {@link CompilerState.create}
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ICompilerStateCreateOptions {
|
||||
/**
|
||||
* Additional .d.ts files to include in the analysis.
|
||||
*/
|
||||
additionalEntryPoints?: string[];
|
||||
|
||||
/**
|
||||
* {@inheritDoc IExtractorInvokeOptions.typescriptCompilerFolder}
|
||||
*/
|
||||
typescriptCompilerFolder?: string | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class represents the TypeScript compiler state. This allows an optimization where multiple invocations
|
||||
* of API Extractor can reuse the same TypeScript compiler analysis.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class CompilerState {
|
||||
/**
|
||||
* The TypeScript compiler's `Program` object, which represents a complete scope of analysis.
|
||||
*/
|
||||
public readonly program: unknown;
|
||||
|
||||
private constructor(properties: CompilerState) {
|
||||
this.program = properties.program;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a compiler state for use with the specified `IExtractorInvokeOptions`.
|
||||
*/
|
||||
public static create(extractorConfig: ExtractorConfig, options?: ICompilerStateCreateOptions): CompilerState {
|
||||
let tsconfig: {} | undefined = extractorConfig.overrideTsconfig;
|
||||
let configBasePath: string = extractorConfig.projectFolder;
|
||||
if (!tsconfig) {
|
||||
// If it wasn't overridden, then load it from disk
|
||||
tsconfig = JsonFile.load(extractorConfig.tsconfigFilePath);
|
||||
configBasePath = path.resolve(path.dirname(extractorConfig.tsconfigFilePath));
|
||||
}
|
||||
|
||||
const commandLine: ts.ParsedCommandLine = ts.parseJsonConfigFileContent(tsconfig, ts.sys, configBasePath);
|
||||
|
||||
if (!commandLine.options.skipLibCheck && extractorConfig.skipLibCheck) {
|
||||
commandLine.options.skipLibCheck = true;
|
||||
console.log(
|
||||
colors.cyan(
|
||||
'API Extractor was invoked with skipLibCheck. This is not recommended and may cause ' +
|
||||
'incorrect type analysis.',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const inputFilePaths: string[] = commandLine.fileNames.concat(extractorConfig.mainEntryPointFilePath);
|
||||
if (options?.additionalEntryPoints) {
|
||||
inputFilePaths.push(...options.additionalEntryPoints);
|
||||
}
|
||||
|
||||
// Append the entry points and remove any non-declaration files from the list
|
||||
const analysisFilePaths: string[] = CompilerState._generateFilePathsForAnalysis(inputFilePaths);
|
||||
|
||||
const compilerHost: ts.CompilerHost = CompilerState._createCompilerHost(commandLine, options);
|
||||
|
||||
const program: ts.Program = ts.createProgram(analysisFilePaths, commandLine.options, compilerHost);
|
||||
|
||||
if (commandLine.errors.length > 0) {
|
||||
const errorText: string = ts.flattenDiagnosticMessageText(commandLine.errors[0]!.messageText, '\n');
|
||||
throw new Error(`Error parsing tsconfig.json content: ${errorText}`);
|
||||
}
|
||||
|
||||
return new CompilerState({
|
||||
program,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of absolute file paths, return a list containing only the declaration
|
||||
* files. Duplicates are also eliminated.
|
||||
*
|
||||
* @remarks
|
||||
* The tsconfig.json settings specify the compiler's input (a set of *.ts source files,
|
||||
* plus some *.d.ts declaration files used for legacy typings). However API Extractor
|
||||
* analyzes the compiler's output (a set of *.d.ts entry point files, plus any legacy
|
||||
* typings). This requires API Extractor to generate a special file list when it invokes
|
||||
* the compiler.
|
||||
*
|
||||
* Duplicates are removed so that entry points can be appended without worrying whether they
|
||||
* may already appear in the tsconfig.json file list.
|
||||
*/
|
||||
private static _generateFilePathsForAnalysis(inputFilePaths: string[]): string[] {
|
||||
const analysisFilePaths: string[] = [];
|
||||
|
||||
const seenFiles: Set<string> = new Set<string>();
|
||||
|
||||
for (const inputFilePath of inputFilePaths) {
|
||||
const inputFileToUpper: string = inputFilePath.toUpperCase();
|
||||
if (!seenFiles.has(inputFileToUpper)) {
|
||||
seenFiles.add(inputFileToUpper);
|
||||
|
||||
if (!path.isAbsolute(inputFilePath)) {
|
||||
throw new Error('Input file is not an absolute path: ' + inputFilePath);
|
||||
}
|
||||
|
||||
if (ExtractorConfig.hasDtsFileExtension(inputFilePath)) {
|
||||
analysisFilePaths.push(inputFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return analysisFilePaths;
|
||||
}
|
||||
|
||||
private static _createCompilerHost(
|
||||
commandLine: ts.ParsedCommandLine,
|
||||
options: IExtractorInvokeOptions | undefined,
|
||||
): ts.CompilerHost {
|
||||
// Create a default CompilerHost that we will override
|
||||
const compilerHost: ts.CompilerHost = ts.createCompilerHost(commandLine.options);
|
||||
|
||||
// Save a copy of the original members. Note that "compilerHost" cannot be the copy, because
|
||||
// createCompilerHost() captures that instance in a closure that is used by the members.
|
||||
const defaultCompilerHost: ts.CompilerHost = { ...compilerHost };
|
||||
|
||||
if (options?.typescriptCompilerFolder) {
|
||||
// Prevent a closure parameter
|
||||
const typescriptCompilerLibFolder: string = path.join(options.typescriptCompilerFolder, 'lib');
|
||||
compilerHost.getDefaultLibLocation = () => typescriptCompilerLibFolder;
|
||||
}
|
||||
|
||||
// Used by compilerHost.fileExists()
|
||||
// .d.ts file path --> whether the file exists
|
||||
const dtsExistsCache: Map<string, boolean> = new Map<string, boolean>();
|
||||
|
||||
// Used by compilerHost.fileExists()
|
||||
// Example: "c:/folder/file.part.ts"
|
||||
const fileExtensionRegExp = /^(?<pathWithoutExtension>.+)(?<fileExtension>\.\w+)$/i;
|
||||
|
||||
compilerHost.fileExists = (fileName: string): boolean => {
|
||||
// In certain deprecated setups, the compiler may write its output files (.js and .d.ts)
|
||||
// in the same folder as the corresponding input file (.ts or .tsx). When following imports,
|
||||
// API Extractor wants to analyze the .d.ts file; however recent versions of the compiler engine
|
||||
// will instead choose the .ts file. To work around this, we hook fileExists() to hide the
|
||||
// existence of those files.
|
||||
|
||||
// Is "fileName" a .d.ts file? The double extension ".d.ts" needs to be matched specially.
|
||||
if (!ExtractorConfig.hasDtsFileExtension(fileName)) {
|
||||
// It's not a .d.ts file. Is the file extension a potential source file?
|
||||
const match: RegExpExecArray | null = fileExtensionRegExp.exec(fileName);
|
||||
if (match?.groups?.pathWithoutExtension && match.groups?.fileExtension) {
|
||||
// Example: "c:/folder/file.part"
|
||||
const pathWithoutExtension: string = match.groups.pathWithoutExtension;
|
||||
// Example: ".ts"
|
||||
const fileExtension: string = match.groups.fileExtension;
|
||||
|
||||
switch (fileExtension.toLocaleLowerCase()) {
|
||||
case '.ts':
|
||||
case '.tsx':
|
||||
case '.js':
|
||||
case '.jsx':
|
||||
// Yes, this is a possible source file. Is there a corresponding .d.ts file in the same folder?
|
||||
const dtsFileName = `${pathWithoutExtension}.d.ts`;
|
||||
|
||||
let dtsFileExists: boolean | undefined = dtsExistsCache.get(dtsFileName);
|
||||
if (dtsFileExists === undefined) {
|
||||
dtsFileExists = defaultCompilerHost.fileExists!(dtsFileName);
|
||||
dtsExistsCache.set(dtsFileName, dtsFileExists);
|
||||
}
|
||||
|
||||
if (dtsFileExists) {
|
||||
// fileName is a potential source file and a corresponding .d.ts file exists.
|
||||
// Thus, API Extractor should ignore this file (so the .d.ts file will get analyzed instead).
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fall through to the default implementation
|
||||
return defaultCompilerHost.fileExists!(fileName);
|
||||
};
|
||||
|
||||
return compilerHost;
|
||||
}
|
||||
}
|
||||
82
packages/api-extractor/src/api/ConsoleMessageId.ts
Normal file
82
packages/api-extractor/src/api/ConsoleMessageId.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
/**
|
||||
* Unique identifiers for console messages reported by API Extractor.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* These strings are possible values for the {@link ExtractorMessage.messageId} property
|
||||
* when the `ExtractorMessage.category` is {@link ExtractorMessageCategory.Console}.
|
||||
* @public
|
||||
*/
|
||||
export const enum ConsoleMessageId {
|
||||
/**
|
||||
* "You have changed the public API signature for this project. Updating ___"
|
||||
*/
|
||||
ApiReportCopied = 'console-api-report-copied',
|
||||
|
||||
/**
|
||||
* "The API report file was missing, so a new file was created. Please add this file to Git: ___"
|
||||
*/
|
||||
ApiReportCreated = 'console-api-report-created',
|
||||
|
||||
/**
|
||||
* "Unable to create the API report file. Please make sure the target folder exists: ___"
|
||||
*/
|
||||
ApiReportFolderMissing = 'console-api-report-folder-missing',
|
||||
|
||||
/**
|
||||
* "You have changed the public API signature for this project.
|
||||
* Please copy the file ___ to ___, or perform a local build (which does this automatically).
|
||||
* See the Git repo documentation for more info."
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* "The API report file is missing.
|
||||
* Please copy the file ___ to ___, or perform a local build (which does this automatically).
|
||||
* See the Git repo documentation for more info."
|
||||
*/
|
||||
ApiReportNotCopied = 'console-api-report-not-copied',
|
||||
|
||||
/**
|
||||
* "The API report is up to date: ___"
|
||||
*/
|
||||
ApiReportUnchanged = 'console-api-report-unchanged',
|
||||
|
||||
/**
|
||||
* "The target project appears to use TypeScript ___ which is newer than the bundled compiler engine;
|
||||
* consider upgrading API Extractor."
|
||||
*/
|
||||
CompilerVersionNotice = 'console-compiler-version-notice',
|
||||
|
||||
/**
|
||||
* Used for the information printed when the "--diagnostics" flag is enabled.
|
||||
*/
|
||||
Diagnostics = 'console-diagnostics',
|
||||
|
||||
/**
|
||||
* "Found metadata in ___"
|
||||
*/
|
||||
FoundTSDocMetadata = 'console-found-tsdoc-metadata',
|
||||
|
||||
/**
|
||||
* "Analysis will use the bundled TypeScript version ___"
|
||||
*/
|
||||
Preamble = 'console-preamble',
|
||||
|
||||
/**
|
||||
* "Using custom TSDoc config from ___"
|
||||
*/
|
||||
UsingCustomTSDocConfig = 'console-using-custom-tsdoc-config',
|
||||
|
||||
/**
|
||||
* "Writing: ___"
|
||||
*/
|
||||
WritingDocModelFile = 'console-writing-doc-model-file',
|
||||
|
||||
/**
|
||||
* "Writing package typings: ___"
|
||||
*/
|
||||
WritingDtsRollup = 'console-writing-dts-rollup',
|
||||
}
|
||||
467
packages/api-extractor/src/api/Extractor.ts
Normal file
467
packages/api-extractor/src/api/Extractor.ts
Normal file
@@ -0,0 +1,467 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
import * as path from 'node:path';
|
||||
import type { ApiPackage } from '@discordjs/api-extractor-model';
|
||||
import { TSDocConfigFile } from '@microsoft/tsdoc-config';
|
||||
import {
|
||||
FileSystem,
|
||||
type NewlineKind,
|
||||
PackageJsonLookup,
|
||||
type IPackageJson,
|
||||
type INodePackageJson,
|
||||
Path,
|
||||
} from '@rushstack/node-core-library';
|
||||
import * as resolve from 'resolve';
|
||||
import * as semver from 'semver';
|
||||
import * as ts from 'typescript';
|
||||
import { PackageMetadataManager } from '../analyzer/PackageMetadataManager.js';
|
||||
import { Collector } from '../collector/Collector.js';
|
||||
import { MessageRouter } from '../collector/MessageRouter.js';
|
||||
import { SourceMapper } from '../collector/SourceMapper.js';
|
||||
import { DocCommentEnhancer } from '../enhancers/DocCommentEnhancer.js';
|
||||
import { ValidationEnhancer } from '../enhancers/ValidationEnhancer.js';
|
||||
import { ApiModelGenerator } from '../generators/ApiModelGenerator.js';
|
||||
import { ApiReportGenerator } from '../generators/ApiReportGenerator.js';
|
||||
import { DtsRollupGenerator, DtsRollupKind } from '../generators/DtsRollupGenerator.js';
|
||||
import { CompilerState } from './CompilerState.js';
|
||||
import { ConsoleMessageId } from './ConsoleMessageId.js';
|
||||
import { ExtractorConfig } from './ExtractorConfig.js';
|
||||
import type { ExtractorMessage } from './ExtractorMessage.js';
|
||||
|
||||
/**
|
||||
* Runtime options for Extractor.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface IExtractorInvokeOptions {
|
||||
/**
|
||||
* An optional TypeScript compiler state. This allows an optimization where multiple invocations of API Extractor
|
||||
* can reuse the same TypeScript compiler analysis.
|
||||
*/
|
||||
compilerState?: CompilerState;
|
||||
|
||||
/**
|
||||
* Indicates that API Extractor is running as part of a local build, e.g. on developer's
|
||||
* machine.
|
||||
*
|
||||
* @remarks
|
||||
* This disables certain validation that would normally be performed for a ship/production build. For example,
|
||||
* the *.api.md report file is automatically updated in a local build.
|
||||
*
|
||||
* The default value is false.
|
||||
*/
|
||||
localBuild?: boolean;
|
||||
|
||||
/**
|
||||
* An optional callback function that will be called for each `ExtractorMessage` before it is displayed by
|
||||
* API Extractor. The callback can customize the message, handle it, or discard it.
|
||||
*
|
||||
* @remarks
|
||||
* If a `messageCallback` is not provided, then by default API Extractor will print the messages to
|
||||
* the STDERR/STDOUT console.
|
||||
*/
|
||||
messageCallback?(this: void, message: ExtractorMessage): void;
|
||||
|
||||
/**
|
||||
* If true, API Extractor will print diagnostic information used for troubleshooting problems.
|
||||
* These messages will be included as {@link ExtractorLogLevel.Verbose} output.
|
||||
*
|
||||
* @remarks
|
||||
* Setting `showDiagnostics=true` forces `showVerboseMessages=true`.
|
||||
*/
|
||||
showDiagnostics?: boolean;
|
||||
|
||||
/**
|
||||
* If true, API Extractor will include {@link ExtractorLogLevel.Verbose} messages in its output.
|
||||
*/
|
||||
showVerboseMessages?: boolean;
|
||||
|
||||
/**
|
||||
* Specifies an alternate folder path to be used when loading the TypeScript system typings.
|
||||
*
|
||||
* @remarks
|
||||
* API Extractor uses its own TypeScript compiler engine to analyze your project. If your project
|
||||
* is built with a significantly different TypeScript version, sometimes API Extractor may report compilation
|
||||
* errors due to differences in the system typings (e.g. lib.dom.d.ts). You can use the "--typescriptCompilerFolder"
|
||||
* option to specify the folder path where you installed the TypeScript package, and API Extractor's compiler will
|
||||
* use those system typings instead.
|
||||
*/
|
||||
typescriptCompilerFolder?: string | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* This object represents the outcome of an invocation of API Extractor.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class ExtractorResult {
|
||||
/**
|
||||
* The TypeScript compiler state that was used.
|
||||
*/
|
||||
public readonly compilerState: CompilerState;
|
||||
|
||||
/**
|
||||
* The API Extractor configuration that was used.
|
||||
*/
|
||||
public readonly extractorConfig: ExtractorConfig;
|
||||
|
||||
/**
|
||||
* Whether the invocation of API Extractor was successful. For example, if `succeeded` is false, then the build task
|
||||
* would normally return a nonzero process exit code, indicating that the operation failed.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Normally the operation "succeeds" if `errorCount` and `warningCount` are both zero. However if
|
||||
* {@link IExtractorInvokeOptions.localBuild} is `true`, then the operation "succeeds" if `errorCount` is zero
|
||||
* (i.e. warnings are ignored).
|
||||
*/
|
||||
public readonly succeeded: boolean;
|
||||
|
||||
/**
|
||||
* Returns true if the API report was found to have changed.
|
||||
*/
|
||||
public readonly apiReportChanged: boolean;
|
||||
|
||||
/**
|
||||
* Reports the number of errors encountered during analysis.
|
||||
*
|
||||
* @remarks
|
||||
* This does not count exceptions, where unexpected issues prematurely abort the operation.
|
||||
*/
|
||||
public readonly errorCount: number;
|
||||
|
||||
/**
|
||||
* Reports the number of warnings encountered during analysis.
|
||||
*
|
||||
* @remarks
|
||||
* This does not count warnings that are emitted in the API report file.
|
||||
*/
|
||||
public readonly warningCount: number;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public constructor(properties: ExtractorResult) {
|
||||
this.compilerState = properties.compilerState;
|
||||
this.extractorConfig = properties.extractorConfig;
|
||||
this.succeeded = properties.succeeded;
|
||||
this.apiReportChanged = properties.apiReportChanged;
|
||||
this.errorCount = properties.errorCount;
|
||||
this.warningCount = properties.warningCount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The starting point for invoking the API Extractor tool.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class Extractor {
|
||||
/**
|
||||
* Returns the version number of the API Extractor NPM package.
|
||||
*/
|
||||
public static get version(): string {
|
||||
return Extractor._getPackageJson().version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the package name of the API Extractor NPM package.
|
||||
*/
|
||||
public static get packageName(): string {
|
||||
return Extractor._getPackageJson().name;
|
||||
}
|
||||
|
||||
private static _getPackageJson(): IPackageJson {
|
||||
return PackageJsonLookup.loadOwnPackageJson(__dirname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the api-extractor.json config file from the specified path, and then invoke API Extractor.
|
||||
*/
|
||||
public static loadConfigAndInvoke(configFilePath: string, options?: IExtractorInvokeOptions): ExtractorResult {
|
||||
const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare(configFilePath);
|
||||
|
||||
return Extractor.invoke(extractorConfig, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke API Extractor using an already prepared `ExtractorConfig` object.
|
||||
*/
|
||||
public static invoke(extractorConfig: ExtractorConfig, options?: IExtractorInvokeOptions): ExtractorResult {
|
||||
const ioptions = options ?? {};
|
||||
|
||||
const localBuild: boolean = ioptions.localBuild ?? false;
|
||||
|
||||
let compilerState: CompilerState | undefined;
|
||||
if (ioptions.compilerState) {
|
||||
compilerState = ioptions.compilerState;
|
||||
} else {
|
||||
compilerState = CompilerState.create(extractorConfig, ioptions);
|
||||
}
|
||||
|
||||
const sourceMapper: SourceMapper = new SourceMapper();
|
||||
|
||||
const messageRouter: MessageRouter = new MessageRouter({
|
||||
workingPackageFolder: extractorConfig.packageFolder,
|
||||
messageCallback: ioptions.messageCallback,
|
||||
messagesConfig: extractorConfig.messages || {},
|
||||
showVerboseMessages: Boolean(ioptions.showVerboseMessages),
|
||||
showDiagnostics: Boolean(ioptions.showDiagnostics),
|
||||
tsdocConfiguration: extractorConfig.tsdocConfiguration,
|
||||
sourceMapper,
|
||||
});
|
||||
|
||||
if (
|
||||
extractorConfig.tsdocConfigFile.filePath &&
|
||||
!extractorConfig.tsdocConfigFile.fileNotFound &&
|
||||
!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,
|
||||
sourceMapper,
|
||||
});
|
||||
|
||||
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 = 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)) {
|
||||
messageRouter.logVerbose(
|
||||
ConsoleMessageId.ApiReportUnchanged,
|
||||
`The API report is up to date: ${actualApiReportShortPath}`,
|
||||
);
|
||||
} else {
|
||||
apiReportChanged = true;
|
||||
|
||||
if (localBuild) {
|
||||
// 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 {
|
||||
// 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 {
|
||||
// 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) {
|
||||
const expectedApiReportFolder: string = path.dirname(expectedApiReportPath);
|
||||
if (FileSystem.exists(expectedApiReportFolder)) {
|
||||
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,
|
||||
);
|
||||
} else {
|
||||
messageRouter.logError(
|
||||
ConsoleMessageId.ApiReportFolderMissing,
|
||||
'Unable to create the API report file. Please make sure the target folder exists:\n' +
|
||||
expectedApiReportFolder,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 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.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (extractorConfig.rollupEnabled) {
|
||||
Extractor._generateRollupDtsFile(
|
||||
collector,
|
||||
extractorConfig.publicTrimmedFilePath,
|
||||
DtsRollupKind.PublicRelease,
|
||||
extractorConfig.newlineKind,
|
||||
);
|
||||
Extractor._generateRollupDtsFile(
|
||||
collector,
|
||||
extractorConfig.alphaTrimmedFilePath,
|
||||
DtsRollupKind.AlphaRelease,
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
||||
private static _checkCompilerCompatibility(extractorConfig: ExtractorConfig, messageRouter: MessageRouter): void {
|
||||
messageRouter.logInfo(ConsoleMessageId.Preamble, `Analysis will use the bundled TypeScript version ${ts.version}`);
|
||||
|
||||
try {
|
||||
const typescriptPath: string = resolve.sync('typescript', {
|
||||
basedir: extractorConfig.projectFolder,
|
||||
preserveSymlinks: false,
|
||||
});
|
||||
const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup();
|
||||
const packageJson: INodePackageJson | undefined = packageJsonLookup.tryLoadNodePackageJsonFor(typescriptPath);
|
||||
if (packageJson?.version && semver.valid(packageJson.version)) {
|
||||
// Consider a newer MINOR release to be incompatible
|
||||
const ourMajor: number = semver.major(ts.version);
|
||||
const ourMinor: number = semver.minor(ts.version);
|
||||
|
||||
const theirMajor: number = semver.major(packageJson.version);
|
||||
const theirMinor: number = semver.minor(packageJson.version);
|
||||
|
||||
if (theirMajor > ourMajor || (theirMajor === ourMajor && theirMinor > ourMinor)) {
|
||||
messageRouter.logInfo(
|
||||
ConsoleMessageId.CompilerVersionNotice,
|
||||
`*** The target project appears to use TypeScript ${packageJson.version} which is newer than the` +
|
||||
` bundled compiler engine; consider upgrading API Extractor.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// The compiler detection heuristic is not expected to work in many configurations
|
||||
}
|
||||
}
|
||||
|
||||
private static _generateRollupDtsFile(
|
||||
collector: Collector,
|
||||
outputPath: string,
|
||||
dtsKind: DtsRollupKind,
|
||||
newlineKind: NewlineKind,
|
||||
): void {
|
||||
if (outputPath !== '') {
|
||||
collector.messageRouter.logVerbose(ConsoleMessageId.WritingDtsRollup, `Writing package typings: ${outputPath}`);
|
||||
DtsRollupGenerator.writeTypingsFile(collector, outputPath, dtsKind, newlineKind);
|
||||
}
|
||||
}
|
||||
}
|
||||
1196
packages/api-extractor/src/api/ExtractorConfig.ts
Normal file
1196
packages/api-extractor/src/api/ExtractorConfig.ts
Normal file
File diff suppressed because it is too large
Load Diff
48
packages/api-extractor/src/api/ExtractorLogLevel.ts
Normal file
48
packages/api-extractor/src/api/ExtractorLogLevel.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
/**
|
||||
* Used with {@link IConfigMessageReportingRule.logLevel} and {@link IExtractorInvokeOptions.messageCallback}.
|
||||
*
|
||||
* @remarks
|
||||
* This is part of the {@link IConfigFile} structure.
|
||||
* @public
|
||||
*/
|
||||
export const enum ExtractorLogLevel {
|
||||
/**
|
||||
* The message will be displayed as an error.
|
||||
*
|
||||
* @remarks
|
||||
* Errors typically cause the build to fail and return a nonzero exit code.
|
||||
*/
|
||||
Error = 'error',
|
||||
|
||||
/**
|
||||
* The message will be displayed as an informational message.
|
||||
*
|
||||
* @remarks
|
||||
* Informational messages may contain newlines to ensure nice formatting of the output,
|
||||
* however word-wrapping is the responsibility of the message handler.
|
||||
*/
|
||||
Info = 'info',
|
||||
|
||||
/**
|
||||
* The message will be discarded entirely.
|
||||
*/
|
||||
None = 'none',
|
||||
|
||||
/**
|
||||
* The message will be displayed only when "verbose" output is requested, e.g. using the `--verbose`
|
||||
* command line option.
|
||||
*/
|
||||
Verbose = 'verbose',
|
||||
|
||||
/**
|
||||
* The message will be displayed as an warning.
|
||||
*
|
||||
* @remarks
|
||||
* Warnings typically cause a production build fail and return a nonzero exit code. For a non-production build
|
||||
* (e.g. using the `--local` option with `api-extractor run`), the warning is displayed but the build will not fail.
|
||||
*/
|
||||
Warning = 'warning',
|
||||
}
|
||||
238
packages/api-extractor/src/api/ExtractorMessage.ts
Normal file
238
packages/api-extractor/src/api/ExtractorMessage.ts
Normal file
@@ -0,0 +1,238 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
import type * as tsdoc from '@microsoft/tsdoc';
|
||||
import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter.js';
|
||||
import type { ConsoleMessageId } from './ConsoleMessageId.js';
|
||||
import { ExtractorLogLevel } from './ExtractorLogLevel.js';
|
||||
import type { ExtractorMessageId } from './ExtractorMessageId.js';
|
||||
|
||||
/**
|
||||
* Used by {@link ExtractorMessage.properties}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface IExtractorMessageProperties {
|
||||
/**
|
||||
* A declaration can have multiple names if it is exported more than once.
|
||||
* If an `ExtractorMessage` applies to a specific export name, this property can indicate that.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Used by {@link ExtractorMessageId.InternalMissingUnderscore}.
|
||||
*/
|
||||
readonly exportName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a category of messages for use with {@link ExtractorMessage}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const enum ExtractorMessageCategory {
|
||||
/**
|
||||
* Messages originating from the TypeScript compiler.
|
||||
*
|
||||
* @remarks
|
||||
* These strings begin with the prefix "TS" and have a numeric error code.
|
||||
* Example: `TS2551`
|
||||
*/
|
||||
Compiler = 'Compiler',
|
||||
|
||||
/**
|
||||
* Console messages communicate the progress of the overall operation. They may include newlines to ensure
|
||||
* nice formatting. They are output in real time, and cannot be routed to the API Report file.
|
||||
*
|
||||
* @remarks
|
||||
* These strings begin with the prefix "console-".
|
||||
* Example: `console-writing-typings-file`
|
||||
*/
|
||||
Console = 'console',
|
||||
|
||||
/**
|
||||
* Messages related to API Extractor's analysis.
|
||||
*
|
||||
* @remarks
|
||||
* These strings begin with the prefix "ae-".
|
||||
* Example: `ae-extra-release-tag`
|
||||
*/
|
||||
Extractor = 'Extractor',
|
||||
|
||||
/**
|
||||
* Messages related to parsing of TSDoc comments.
|
||||
*
|
||||
* @remarks
|
||||
* These strings begin with the prefix "tsdoc-".
|
||||
* Example: `tsdoc-link-tag-unescaped-text`
|
||||
*/
|
||||
TSDoc = 'TSDoc',
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor options for `ExtractorMessage`.
|
||||
*/
|
||||
export interface IExtractorMessageOptions {
|
||||
category: ExtractorMessageCategory;
|
||||
logLevel?: ExtractorLogLevel;
|
||||
messageId: ConsoleMessageId | ExtractorMessageId | tsdoc.TSDocMessageId | string;
|
||||
properties?: IExtractorMessageProperties | undefined;
|
||||
sourceFileColumn?: number;
|
||||
sourceFileLine?: number;
|
||||
sourceFilePath?: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* This object is used to report an error or warning that occurred during API Extractor's analysis.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class ExtractorMessage {
|
||||
private _handled: boolean;
|
||||
|
||||
private _logLevel: ExtractorLogLevel;
|
||||
|
||||
/**
|
||||
* The category of issue.
|
||||
*/
|
||||
public readonly category: ExtractorMessageCategory;
|
||||
|
||||
/**
|
||||
* A text string that uniquely identifies the issue type. This identifier can be used to suppress
|
||||
* or configure the reporting of issues, and also to search for help about an issue.
|
||||
*/
|
||||
public readonly messageId: ConsoleMessageId | ExtractorMessageId | tsdoc.TSDocMessageId | string;
|
||||
|
||||
/**
|
||||
* The text description of this issue.
|
||||
*/
|
||||
public readonly text: string;
|
||||
|
||||
/**
|
||||
* The absolute path to the affected input source file, if there is one.
|
||||
*/
|
||||
public readonly sourceFilePath: string | undefined;
|
||||
|
||||
/**
|
||||
* The line number where the issue occurred in the input source file. This is not used if `sourceFilePath`
|
||||
* is undefined. The first line number is 1.
|
||||
*/
|
||||
public readonly sourceFileLine: number | undefined;
|
||||
|
||||
/**
|
||||
* The column number where the issue occurred in the input source file. This is not used if `sourceFilePath`
|
||||
* is undefined. The first column number is 1.
|
||||
*/
|
||||
public readonly sourceFileColumn: number | undefined;
|
||||
|
||||
/**
|
||||
* Additional contextual information about the message that may be useful when reporting errors.
|
||||
* All properties are optional.
|
||||
*/
|
||||
public readonly properties: IExtractorMessageProperties;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public constructor(options: IExtractorMessageOptions) {
|
||||
this.category = options.category;
|
||||
this.messageId = options.messageId;
|
||||
this.text = options.text;
|
||||
this.sourceFilePath = options.sourceFilePath;
|
||||
this.sourceFileLine = options.sourceFileLine;
|
||||
this.sourceFileColumn = options.sourceFileColumn;
|
||||
this.properties = options.properties ?? {};
|
||||
|
||||
this._handled = false;
|
||||
this._logLevel = options.logLevel ?? ExtractorLogLevel.None;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the {@link IExtractorInvokeOptions.messageCallback} sets this property to true, it will prevent the message
|
||||
* from being displayed by API Extractor.
|
||||
*
|
||||
* @remarks
|
||||
* If the `messageCallback` routes the message to a custom handler (e.g. a toolchain logger), it should
|
||||
* assign `handled = true` to prevent API Extractor from displaying it. Assigning `handled = true` for all messages
|
||||
* would effectively disable all console output from the `Extractor` API.
|
||||
*
|
||||
* If `handled` is set to true, the message will still be included in the count of errors/warnings;
|
||||
* to discard a message entirely, instead assign `logLevel = none`.
|
||||
*/
|
||||
public get handled(): boolean {
|
||||
return this._handled;
|
||||
}
|
||||
|
||||
public set handled(value: boolean) {
|
||||
if (this._handled && !value) {
|
||||
throw new Error('One a message has been marked as handled, the "handled" property cannot be set to false');
|
||||
}
|
||||
|
||||
this._handled = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies how the message should be reported.
|
||||
*
|
||||
* @remarks
|
||||
* If the {@link IExtractorInvokeOptions.messageCallback} handles the message (i.e. sets `handled = true`),
|
||||
* it can use the `logLevel` to determine how to display the message.
|
||||
*
|
||||
* Alternatively, if API Extractor is handling the message, the `messageCallback` could assign `logLevel` to change
|
||||
* how it will be processed. However, in general the recommended practice is to configure message routing
|
||||
* using the `messages` section in api-extractor.json.
|
||||
*
|
||||
* To discard a message entirely, assign `logLevel = none`.
|
||||
*/
|
||||
public get logLevel(): ExtractorLogLevel {
|
||||
return this._logLevel;
|
||||
}
|
||||
|
||||
public set logLevel(value: ExtractorLogLevel) {
|
||||
switch (value) {
|
||||
case ExtractorLogLevel.Error:
|
||||
case ExtractorLogLevel.Info:
|
||||
case ExtractorLogLevel.None:
|
||||
case ExtractorLogLevel.Verbose:
|
||||
case ExtractorLogLevel.Warning:
|
||||
break;
|
||||
default:
|
||||
throw new Error('Invalid log level');
|
||||
}
|
||||
|
||||
this._logLevel = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message formatted with its identifier and file position.
|
||||
*
|
||||
* @remarks
|
||||
* Example:
|
||||
* ```
|
||||
* src/folder/File.ts:123:4 - (ae-extra-release-tag) The doc comment should not contain more than one release tag.
|
||||
* ```
|
||||
*/
|
||||
public formatMessageWithLocation(workingPackageFolderPath: string | undefined): string {
|
||||
let result = '';
|
||||
|
||||
if (this.sourceFilePath) {
|
||||
result += SourceFileLocationFormatter.formatPath(this.sourceFilePath, {
|
||||
sourceFileLine: this.sourceFileLine,
|
||||
sourceFileColumn: this.sourceFileColumn,
|
||||
workingPackageFolderPath,
|
||||
});
|
||||
|
||||
if (result.length > 0) {
|
||||
result += ' - ';
|
||||
}
|
||||
}
|
||||
|
||||
result += this.formatMessageWithoutLocation();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public formatMessageWithoutLocation(): string {
|
||||
return `(${this.messageId}) ${this.text}`;
|
||||
}
|
||||
}
|
||||
145
packages/api-extractor/src/api/ExtractorMessageId.ts
Normal file
145
packages/api-extractor/src/api/ExtractorMessageId.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
/**
|
||||
* Unique identifiers for messages reported by API Extractor during its analysis.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* These strings are possible values for the {@link ExtractorMessage.messageId} property
|
||||
* when the `ExtractorMessage.category` is {@link ExtractorMessageCategory.Extractor}.
|
||||
* @public
|
||||
*/
|
||||
export const enum ExtractorMessageId {
|
||||
/**
|
||||
* "The `@inheritDoc` tag for ___ refers to its own declaration."
|
||||
*/
|
||||
CyclicInheritDoc = 'ae-cyclic-inherit-doc',
|
||||
|
||||
/**
|
||||
* "This symbol has another declaration with a different release tag."
|
||||
*/
|
||||
DifferentReleaseTags = 'ae-different-release-tags',
|
||||
|
||||
/**
|
||||
* "The doc comment should not contain more than one release tag."
|
||||
*/
|
||||
ExtraReleaseTag = 'ae-extra-release-tag',
|
||||
|
||||
/**
|
||||
* "The symbol ___ needs to be exported by the entry point ___."
|
||||
*/
|
||||
ForgottenExport = 'ae-forgotten-export',
|
||||
|
||||
/**
|
||||
* "The symbol ___ is marked as ___, but its signature references ___ which is marked as ___."
|
||||
*/
|
||||
IncompatibleReleaseTags = 'ae-incompatible-release-tags',
|
||||
|
||||
/**
|
||||
* "The name ___ should be prefixed with an underscore because the declaration is marked as `@internal`."
|
||||
*/
|
||||
InternalMissingUnderscore = 'ae-internal-missing-underscore',
|
||||
|
||||
/**
|
||||
* "Mixed release tags are not allowed for ___ because one of its declarations is marked as `@internal`."
|
||||
*/
|
||||
InternalMixedReleaseTag = 'ae-internal-mixed-release-tag',
|
||||
|
||||
/**
|
||||
* "The `@packageDocumentation` comment must appear at the top of entry point *.d.ts file."
|
||||
*/
|
||||
MisplacedPackageTag = 'ae-misplaced-package-tag',
|
||||
|
||||
/**
|
||||
* "The property ___ has a setter but no getter."
|
||||
*/
|
||||
MissingGetter = 'ae-missing-getter',
|
||||
|
||||
/**
|
||||
* "___ is part of the package's API, but it is missing a release tag (`@alpha`, `@beta`, `@public`, or `@internal`)."
|
||||
*/
|
||||
MissingReleaseTag = 'ae-missing-release-tag',
|
||||
|
||||
/**
|
||||
* "The `@preapproved` tag cannot be applied to ___ without an `@internal` release tag."
|
||||
*/
|
||||
PreapprovedBadReleaseTag = 'ae-preapproved-bad-release-tag',
|
||||
|
||||
/**
|
||||
* "The `@preapproved` tag cannot be applied to ___ because it is not a supported declaration type."
|
||||
*/
|
||||
PreapprovedUnsupportedType = 'ae-preapproved-unsupported-type',
|
||||
|
||||
/**
|
||||
* "The doc comment for the property ___ must appear on the getter, not the setter."
|
||||
*/
|
||||
SetterWithDocs = 'ae-setter-with-docs',
|
||||
|
||||
/**
|
||||
* "Missing documentation for ___."
|
||||
*
|
||||
* @remarks
|
||||
* The `ae-undocumented` message is only generated if the API report feature is enabled.
|
||||
*
|
||||
* Because the API report file already annotates undocumented items with `// (undocumented)`,
|
||||
* the `ae-undocumented` message is not logged by default. To see it, add a setting such as:
|
||||
* ```json
|
||||
* "messages": {
|
||||
* "extractorMessageReporting": {
|
||||
* "ae-undocumented": {
|
||||
* "logLevel": "warning"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
Undocumented = 'ae-undocumented',
|
||||
|
||||
/**
|
||||
* "The `@inheritDoc` tag needs a TSDoc declaration reference; signature matching is not supported yet."
|
||||
*
|
||||
* @privateRemarks
|
||||
* In the future, we will implement signature matching so that you can write `{@inheritDoc}` and API Extractor
|
||||
* will find a corresponding member from a base class (or implemented interface). Until then, the tag
|
||||
* always needs an explicit declaration reference such as `{@inhertDoc MyBaseClass.sameMethod}`.
|
||||
*/
|
||||
UnresolvedInheritDocBase = 'ae-unresolved-inheritdoc-base',
|
||||
|
||||
/**
|
||||
* "The `@inheritDoc` reference could not be resolved."
|
||||
*/
|
||||
UnresolvedInheritDocReference = 'ae-unresolved-inheritdoc-reference',
|
||||
|
||||
/**
|
||||
* "The `@link` reference could not be resolved."
|
||||
*/
|
||||
UnresolvedLink = 'ae-unresolved-link',
|
||||
|
||||
/**
|
||||
* "Incorrect file type; API Extractor expects to analyze compiler outputs with the .d.ts file extension.
|
||||
* Troubleshooting tips: `https://api-extractor.com/link/dts-error`"
|
||||
*/
|
||||
WrongInputFileType = 'ae-wrong-input-file-type',
|
||||
}
|
||||
|
||||
export const allExtractorMessageIds: Set<string> = new Set<string>([
|
||||
'ae-extra-release-tag',
|
||||
'ae-undocumented',
|
||||
'ae-different-release-tags',
|
||||
'ae-incompatible-release-tags',
|
||||
'ae-missing-release-tag',
|
||||
'ae-misplaced-package-tag',
|
||||
'ae-forgotten-export',
|
||||
'ae-internal-missing-underscore',
|
||||
'ae-internal-mixed-release-tag',
|
||||
'ae-preapproved-unsupported-type',
|
||||
'ae-preapproved-bad-release-tag',
|
||||
'ae-unresolved-inheritdoc-reference',
|
||||
'ae-unresolved-inheritdoc-base',
|
||||
'ae-cyclic-inherit-doc',
|
||||
'ae-unresolved-link',
|
||||
'ae-setter-with-docs',
|
||||
'ae-missing-getter',
|
||||
'ae-wrong-input-file-type',
|
||||
]);
|
||||
448
packages/api-extractor/src/api/IConfigFile.ts
Normal file
448
packages/api-extractor/src/api/IConfigFile.ts
Normal file
@@ -0,0 +1,448 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
import type { EnumMemberOrder } from '@discordjs/api-extractor-model';
|
||||
import type { ExtractorLogLevel } from './ExtractorLogLevel.js';
|
||||
|
||||
/**
|
||||
* Determines how the TypeScript compiler engine will be invoked by API Extractor.
|
||||
*
|
||||
* @remarks
|
||||
* This is part of the {@link IConfigFile} structure.
|
||||
* @public
|
||||
*/
|
||||
export interface IConfigCompiler {
|
||||
/**
|
||||
* Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk.
|
||||
*
|
||||
* @remarks
|
||||
* The value must conform to the TypeScript tsconfig schema:
|
||||
*
|
||||
* http://json.schemastore.org/tsconfig
|
||||
*
|
||||
* If omitted, then the tsconfig.json file will instead be read from the projectFolder.
|
||||
*/
|
||||
overrideTsconfig?: {};
|
||||
|
||||
/**
|
||||
* This option causes the compiler to be invoked with the `--skipLibCheck` option.
|
||||
*
|
||||
* @remarks
|
||||
* This option is not recommended and may cause API Extractor to produce incomplete or incorrect declarations,
|
||||
* but it may be required when dependencies contain declarations that are incompatible with the TypeScript engine
|
||||
* that API Extractor uses for its analysis. Where possible, the underlying issue should be fixed rather than
|
||||
* relying on skipLibCheck.
|
||||
*/
|
||||
skipLibCheck?: boolean;
|
||||
|
||||
/**
|
||||
* Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project.
|
||||
*
|
||||
* @remarks
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as `<projectFolder>`.
|
||||
*
|
||||
* Note: This setting will be ignored if `overrideTsconfig` is used.
|
||||
*/
|
||||
tsconfigFilePath?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures how the API report files (*.api.md) will be generated.
|
||||
*
|
||||
* @remarks
|
||||
* This is part of the {@link IConfigFile} structure.
|
||||
* @public
|
||||
*/
|
||||
export interface IConfigApiReport {
|
||||
/**
|
||||
* Whether to generate an API report.
|
||||
*/
|
||||
enabled: boolean;
|
||||
|
||||
/**
|
||||
* Whether "forgotten exports" should be included in the API report file.
|
||||
*
|
||||
* @remarks
|
||||
* Forgotten exports are declarations flagged with `ae-forgotten-export` warnings. See
|
||||
* https://api-extractor.com/pages/messages/ae-forgotten-export/ to learn more.
|
||||
* @defaultValue `false`
|
||||
*/
|
||||
includeForgottenExports?: boolean;
|
||||
|
||||
/**
|
||||
* The filename for the API report files. It will be combined with `reportFolder` or `reportTempFolder` to produce
|
||||
* a full output filename.
|
||||
*
|
||||
* @remarks
|
||||
* The file extension should be ".api.md", and the string should not contain a path separator such as `\` or `/`.
|
||||
*/
|
||||
reportFileName?: string;
|
||||
|
||||
/**
|
||||
* Specifies the folder where the API report file is written. The file name portion is determined by
|
||||
* the `reportFileName` setting.
|
||||
*
|
||||
* @remarks
|
||||
* The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy,
|
||||
* e.g. for an API review.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as `<projectFolder>`.
|
||||
*/
|
||||
reportFolder?: string;
|
||||
|
||||
/**
|
||||
* Specifies the folder where the temporary report file is written. The file name portion is determined by
|
||||
* the `reportFileName` setting.
|
||||
*
|
||||
* @remarks
|
||||
* After the temporary file is written to disk, it is compared with the file in the `reportFolder`.
|
||||
* If they are different, a production build will fail.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as `<projectFolder>`.
|
||||
*/
|
||||
reportTempFolder?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures how the doc model file (*.api.json) will be generated.
|
||||
*
|
||||
* @remarks
|
||||
* This is part of the {@link IConfigFile} structure.
|
||||
* @public
|
||||
*/
|
||||
export interface IConfigDocModel {
|
||||
/**
|
||||
* The output path for the doc model file. The file extension should be ".api.json".
|
||||
*
|
||||
* @remarks
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as `<projectFolder>`.
|
||||
*/
|
||||
apiJsonFilePath?: string;
|
||||
|
||||
/**
|
||||
* Whether to generate a doc model file.
|
||||
*/
|
||||
enabled: boolean;
|
||||
|
||||
/**
|
||||
* Whether "forgotten exports" should be included in the doc model file.
|
||||
*
|
||||
* @remarks
|
||||
* Forgotten exports are declarations flagged with `ae-forgotten-export` warnings. See
|
||||
* https://api-extractor.com/pages/messages/ae-forgotten-export/ to learn more.
|
||||
* @defaultValue `false`
|
||||
*/
|
||||
includeForgottenExports?: boolean;
|
||||
|
||||
/**
|
||||
* The base URL where the project's source code can be viewed on a website such as GitHub or
|
||||
* Azure DevOps. This URL path corresponds to the `<projectFolder>` path on disk.
|
||||
*
|
||||
* @remarks
|
||||
* This URL is concatenated with the file paths serialized to the doc model to produce URL file paths to individual API items.
|
||||
* For example, if the `projectFolderUrl` is "https://github.com/microsoft/rushstack/tree/main/apps/api-extractor" and an API
|
||||
* item's file path is "api/ExtractorConfig.ts", the full URL file path would be
|
||||
* "https://github.com/microsoft/rushstack/tree/main/apps/api-extractor/api/ExtractorConfig.js".
|
||||
*
|
||||
* Can be omitted if you don't need source code links in your API documentation reference.
|
||||
*/
|
||||
projectFolderUrl?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures how the .d.ts rollup file will be generated.
|
||||
*
|
||||
* @remarks
|
||||
* This is part of the {@link IConfigFile} structure.
|
||||
* @public
|
||||
*/
|
||||
export interface IConfigDtsRollup {
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for an "alpha" release.
|
||||
*
|
||||
* @remarks
|
||||
* This file will include only declarations that are marked as `@public`, `@beta`, or `@alpha`.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as `<projectFolder>`.
|
||||
*/
|
||||
alphaTrimmedFilePath?: string;
|
||||
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release.
|
||||
*
|
||||
* @remarks
|
||||
* This file will include only declarations that are marked as `@public` or `@beta`.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as `<projectFolder>`.
|
||||
*/
|
||||
betaTrimmedFilePath?: string;
|
||||
|
||||
/**
|
||||
* Whether to generate the .d.ts rollup file.
|
||||
*/
|
||||
enabled: boolean;
|
||||
|
||||
/**
|
||||
* When a declaration is trimmed, by default it will be replaced by a code comment such as
|
||||
* "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the
|
||||
* declaration completely.
|
||||
*/
|
||||
omitTrimmingComments?: boolean;
|
||||
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release.
|
||||
*
|
||||
* @remarks
|
||||
* This file will include only declarations that are marked as `@public`.
|
||||
*
|
||||
* If the path is an empty string, then this file will not be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as `<projectFolder>`.
|
||||
*/
|
||||
publicTrimmedFilePath?: string;
|
||||
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated without any trimming.
|
||||
*
|
||||
* @remarks
|
||||
* This file will include all declarations that are exported by the main entry point.
|
||||
*
|
||||
* If the path is an empty string, then this file will not be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as `<projectFolder>`.
|
||||
*/
|
||||
untrimmedFilePath?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures how the tsdoc-metadata.json file will be generated.
|
||||
*
|
||||
* @remarks
|
||||
* This is part of the {@link IConfigFile} structure.
|
||||
* @public
|
||||
*/
|
||||
export interface IConfigTsdocMetadata {
|
||||
/**
|
||||
* Whether to generate the tsdoc-metadata.json file.
|
||||
*/
|
||||
enabled: boolean;
|
||||
|
||||
/**
|
||||
* Specifies where the TSDoc metadata file should be written.
|
||||
*
|
||||
* @remarks
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as `<projectFolder>`.
|
||||
*
|
||||
* The default value is `<lookup>`, which causes the path to be automatically inferred from the `tsdocMetadata`,
|
||||
* `typings` or `main` fields of the project's package.json. If none of these fields are set, the lookup
|
||||
* falls back to `tsdoc-metadata.json` in the package folder.
|
||||
*/
|
||||
tsdocMetadataFilePath?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures reporting for a given message identifier.
|
||||
*
|
||||
* @remarks
|
||||
* This is part of the {@link IConfigFile} structure.
|
||||
* @public
|
||||
*/
|
||||
export interface IConfigMessageReportingRule {
|
||||
/**
|
||||
* When `addToApiReportFile` is true: If API Extractor is configured to write an API report file (.api.md),
|
||||
* then the message will be written inside that file; otherwise, the message is instead logged according to
|
||||
* the `logLevel` option.
|
||||
*/
|
||||
addToApiReportFile?: boolean;
|
||||
|
||||
/**
|
||||
* Specifies whether the message should be written to the the tool's output log.
|
||||
*
|
||||
* @remarks
|
||||
* Note that the `addToApiReportFile` property may supersede this option.
|
||||
*/
|
||||
logLevel: ExtractorLogLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a table of reporting rules for different message identifiers, and also the default rule used for
|
||||
* identifiers that do not appear in the table.
|
||||
*
|
||||
* @remarks
|
||||
* This is part of the {@link IConfigFile} structure.
|
||||
* @public
|
||||
*/
|
||||
export interface IConfigMessageReportingTable {
|
||||
/**
|
||||
* The key is a message identifier for the associated type of message, or "default" to specify the default policy.
|
||||
* For example, the key might be `TS2551` (a compiler message), `tsdoc-link-tag-unescaped-text` (a TSDOc message),
|
||||
* or `ae-extra-release-tag` (a message related to the API Extractor analysis).
|
||||
*/
|
||||
[messageId: string]: IConfigMessageReportingRule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures how API Extractor reports error and warning messages produced during analysis.
|
||||
*
|
||||
* @remarks
|
||||
* This is part of the {@link IConfigFile} structure.
|
||||
* @public
|
||||
*/
|
||||
export interface IExtractorMessagesConfig {
|
||||
/**
|
||||
* Configures handling of diagnostic messages generating the TypeScript compiler while analyzing the
|
||||
* input .d.ts files.
|
||||
*/
|
||||
compilerMessageReporting?: IConfigMessageReportingTable;
|
||||
|
||||
/**
|
||||
* Configures handling of messages reported by API Extractor during its analysis.
|
||||
*/
|
||||
extractorMessageReporting?: IConfigMessageReportingTable;
|
||||
|
||||
/**
|
||||
* Configures handling of messages reported by the TSDoc parser when analyzing code comments.
|
||||
*/
|
||||
tsdocMessageReporting?: IConfigMessageReportingTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration options for the API Extractor tool. These options can be constructed programmatically
|
||||
* or loaded from the api-extractor.json config file using the {@link ExtractorConfig} class.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface IConfigFile {
|
||||
/**
|
||||
* {@inheritDoc IConfigApiReport}
|
||||
*/
|
||||
apiReport?: IConfigApiReport;
|
||||
|
||||
/**
|
||||
* A list of NPM package names whose exports should be treated as part of this package.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* For example, suppose that Webpack is used to generate a distributed bundle for the project `library1`,
|
||||
* and another NPM package `library2` is embedded in this bundle. Some types from `library2` may become part
|
||||
* of the exported API for `library1`, but by default API Extractor would generate a .d.ts rollup that explicitly
|
||||
* imports `library2`. To avoid this, we can specify:
|
||||
*
|
||||
* ```js
|
||||
* "bundledPackages": [ "library2" ],
|
||||
* ```
|
||||
*
|
||||
* This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been
|
||||
* local files for `library1`.
|
||||
*/
|
||||
bundledPackages?: string[];
|
||||
|
||||
/**
|
||||
* {@inheritDoc IConfigCompiler}
|
||||
*/
|
||||
compiler?: IConfigCompiler;
|
||||
|
||||
/**
|
||||
* {@inheritDoc IConfigDocModel}
|
||||
*/
|
||||
docModel?: IConfigDocModel;
|
||||
|
||||
/**
|
||||
* {@inheritDoc IConfigDtsRollup}
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
dtsRollup?: IConfigDtsRollup;
|
||||
|
||||
/**
|
||||
* Specifies how API Extractor sorts members of an enum when generating the .api.json file.
|
||||
*
|
||||
* @remarks
|
||||
* By default, the output files will be sorted alphabetically, which is "by-name".
|
||||
* To keep the ordering in the source code, specify "preserve".
|
||||
* @defaultValue `by-name`
|
||||
*/
|
||||
enumMemberOrder?: EnumMemberOrder;
|
||||
|
||||
/**
|
||||
* Optionally specifies another JSON config file that this file extends from. This provides a way for
|
||||
* standard settings to be shared across multiple projects.
|
||||
*
|
||||
* @remarks
|
||||
* If the path starts with `./` or `../`, the path is resolved relative to the folder of the file that contains
|
||||
* the `extends` field. Otherwise, the first path segment is interpreted as an NPM package name, and will be
|
||||
* resolved using NodeJS `require()`.
|
||||
*/
|
||||
extends?: string;
|
||||
|
||||
/**
|
||||
* Specifies the .d.ts file to be used as the starting point for analysis. API Extractor
|
||||
* analyzes the symbols exported by this module.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* The file extension must be ".d.ts" and not ".ts".
|
||||
* The path is resolved relative to the "projectFolder" location.
|
||||
*/
|
||||
mainEntryPointFilePath: string;
|
||||
|
||||
/**
|
||||
* {@inheritDoc IExtractorMessagesConfig}
|
||||
*/
|
||||
messages?: IExtractorMessagesConfig;
|
||||
|
||||
/**
|
||||
* Specifies what type of newlines API Extractor should use when writing output files.
|
||||
*
|
||||
* @remarks
|
||||
* By default, the output files will be written with Windows-style newlines.
|
||||
* To use POSIX-style newlines, specify "lf" instead.
|
||||
* To use the OS's default newline kind, specify "os".
|
||||
*/
|
||||
newlineKind?: 'crlf' | 'lf' | 'os';
|
||||
|
||||
/**
|
||||
* Determines the `<projectFolder>` token that can be used with other config file settings. The project folder
|
||||
* typically contains the tsconfig.json and package.json config files, but the path is user-defined.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting.
|
||||
*
|
||||
* The default value for `projectFolder` is the token `<lookup>`, which means the folder is determined using
|
||||
* the following heuristics:
|
||||
*
|
||||
* If the config/rig.json system is used (as defined by {@link https://www.npmjs.com/package/@rushstack/rig-package
|
||||
* | @rushstack/rig-package}), then the `<lookup>` value will be the package folder that referenced the rig.
|
||||
*
|
||||
* Otherwise, the `<lookup>` value is determined by traversing parent folders, starting from the folder containing
|
||||
* api-extractor.json, and stopping at the first folder that contains a tsconfig.json file. If a tsconfig.json file
|
||||
* cannot be found in this way, then an error will be reported.
|
||||
*/
|
||||
projectFolder?: string;
|
||||
|
||||
/**
|
||||
* Set to true when invoking API Extractor's test harness.
|
||||
*
|
||||
* @remarks
|
||||
* When `testMode` is true, the `toolVersion` field in the .api.json file is assigned an empty string
|
||||
* to prevent spurious diffs in output files tracked for tests.
|
||||
*/
|
||||
testMode?: boolean;
|
||||
|
||||
/**
|
||||
* {@inheritDoc IConfigTsdocMetadata}
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
tsdocMetadata?: IConfigTsdocMetadata;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
import * as path from 'node:path';
|
||||
import { StandardTags } from '@microsoft/tsdoc';
|
||||
import { ExtractorConfig } from '../ExtractorConfig.js';
|
||||
|
||||
const testDataFolder: string = path.join(__dirname, 'test-data');
|
||||
|
||||
describe('Extractor-custom-tags', () => {
|
||||
describe('should use a TSDocConfiguration', () => {
|
||||
it.only("with custom TSDoc tags defined in the package's tsdoc.json", () => {
|
||||
const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare(
|
||||
path.join(testDataFolder, 'custom-tsdoc-tags/api-extractor.json'),
|
||||
);
|
||||
const { tsdocConfiguration } = extractorConfig;
|
||||
|
||||
expect(tsdocConfiguration.tryGetTagDefinition('@block')).not.toBe(undefined);
|
||||
expect(tsdocConfiguration.tryGetTagDefinition('@inline')).not.toBe(undefined);
|
||||
expect(tsdocConfiguration.tryGetTagDefinition('@modifier')).not.toBe(undefined);
|
||||
});
|
||||
it.only("with custom TSDoc tags enabled per the package's tsdoc.json", () => {
|
||||
const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare(
|
||||
path.join(testDataFolder, 'custom-tsdoc-tags/api-extractor.json'),
|
||||
);
|
||||
const { tsdocConfiguration } = extractorConfig;
|
||||
const block = tsdocConfiguration.tryGetTagDefinition('@block')!;
|
||||
const inline = tsdocConfiguration.tryGetTagDefinition('@inline')!;
|
||||
const modifier = tsdocConfiguration.tryGetTagDefinition('@modifier')!;
|
||||
|
||||
expect(tsdocConfiguration.isTagSupported(block)).toBe(true);
|
||||
expect(tsdocConfiguration.isTagSupported(inline)).toBe(true);
|
||||
expect(tsdocConfiguration.isTagSupported(modifier)).toBe(false);
|
||||
});
|
||||
it.only("with standard tags and API Extractor custom tags defined and supported when the package's tsdoc.json extends API Extractor's tsdoc.json", () => {
|
||||
const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare(
|
||||
path.join(testDataFolder, 'custom-tsdoc-tags/api-extractor.json'),
|
||||
);
|
||||
const { tsdocConfiguration } = extractorConfig;
|
||||
|
||||
expect(tsdocConfiguration.tryGetTagDefinition('@inline')).not.toBe(undefined);
|
||||
expect(tsdocConfiguration.tryGetTagDefinition('@block')).not.toBe(undefined);
|
||||
expect(tsdocConfiguration.tryGetTagDefinition('@modifier')).not.toBe(undefined);
|
||||
|
||||
for (const tag of StandardTags.allDefinitions.concat([
|
||||
tsdocConfiguration.tryGetTagDefinition('@betaDocumentation')!,
|
||||
tsdocConfiguration.tryGetTagDefinition('@internalRemarks')!,
|
||||
tsdocConfiguration.tryGetTagDefinition('@preapproved')!,
|
||||
])) {
|
||||
expect(tsdocConfiguration.tagDefinitions.includes(tag));
|
||||
expect(tsdocConfiguration.supportedTagDefinitions.includes(tag));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
import * as path from 'node:path';
|
||||
import { Path } from '@rushstack/node-core-library';
|
||||
import { ExtractorConfig } from '../ExtractorConfig.js';
|
||||
|
||||
const testDataFolder: string = path.join(__dirname, 'test-data');
|
||||
|
||||
function expectEqualPaths(path1: string, path2: string): void {
|
||||
if (!Path.isEqual(path1, path2)) {
|
||||
fail('Expected paths to be equal:\npath1: ' + path1 + '\npath2: ' + path2);
|
||||
}
|
||||
}
|
||||
|
||||
// Tests for expanding the "<lookup>" token for the "projectFolder" setting in api-extractor.json
|
||||
describe(`${ExtractorConfig.name}.${ExtractorConfig.loadFileAndPrepare.name}`, () => {
|
||||
it.only('config-lookup1: looks up ./api-extractor.json', () => {
|
||||
const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare(
|
||||
path.join(testDataFolder, 'config-lookup1/api-extractor.json'),
|
||||
);
|
||||
expectEqualPaths(extractorConfig.projectFolder, path.join(testDataFolder, 'config-lookup1'));
|
||||
});
|
||||
it.only('config-lookup2: looks up ./config/api-extractor.json', () => {
|
||||
const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare(
|
||||
path.join(testDataFolder, 'config-lookup2/config/api-extractor.json'),
|
||||
);
|
||||
expectEqualPaths(extractorConfig.projectFolder, path.join(testDataFolder, 'config-lookup2'));
|
||||
});
|
||||
it.only('config-lookup3a: looks up ./src/test/config/api-extractor.json', () => {
|
||||
const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare(
|
||||
path.join(testDataFolder, 'config-lookup3/src/test/config/api-extractor.json'),
|
||||
);
|
||||
expectEqualPaths(extractorConfig.projectFolder, path.join(testDataFolder, 'config-lookup3/src/test/'));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
||||
|
||||
"mainEntryPointFilePath": "<projectFolder>/index.d.ts",
|
||||
|
||||
"apiReport": {
|
||||
"enabled": true
|
||||
},
|
||||
|
||||
"docModel": {
|
||||
"enabled": true
|
||||
},
|
||||
|
||||
"dtsRollup": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
2
packages/api-extractor/src/api/test/test-data/config-lookup1/index.d.ts
vendored
Normal file
2
packages/api-extractor/src/api/test/test-data/config-lookup1/index.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/* eslint-disable unicorn/no-empty-file */
|
||||
// empty file
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "config-lookup1",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/tsconfig",
|
||||
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"rootDir": "src",
|
||||
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"experimentalDecorators": true,
|
||||
"strictNullChecks": true,
|
||||
"noUnusedLocals": true,
|
||||
"types": ["heft-jest", "node"],
|
||||
|
||||
"module": "commonjs",
|
||||
"target": "es2017",
|
||||
"lib": ["es2017"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
||||
"exclude": ["node_modules", "lib"]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
||||
|
||||
"mainEntryPointFilePath": "<projectFolder>/index.d.ts",
|
||||
|
||||
"apiReport": {
|
||||
"enabled": true
|
||||
},
|
||||
|
||||
"docModel": {
|
||||
"enabled": true
|
||||
},
|
||||
|
||||
"dtsRollup": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
2
packages/api-extractor/src/api/test/test-data/config-lookup2/index.d.ts
vendored
Normal file
2
packages/api-extractor/src/api/test/test-data/config-lookup2/index.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/* eslint-disable unicorn/no-empty-file */
|
||||
// empty file
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "config-lookup2",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/tsconfig",
|
||||
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"rootDir": "src",
|
||||
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"experimentalDecorators": true,
|
||||
"strictNullChecks": true,
|
||||
"noUnusedLocals": true,
|
||||
"types": ["heft-jest", "node"],
|
||||
|
||||
"module": "commonjs",
|
||||
"target": "es2017",
|
||||
"lib": ["es2017"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
||||
"exclude": ["node_modules", "lib"]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
||||
|
||||
"mainEntryPointFilePath": "<projectFolder>/index.d.ts",
|
||||
|
||||
"apiReport": {
|
||||
"enabled": true
|
||||
},
|
||||
|
||||
"docModel": {
|
||||
"enabled": true
|
||||
},
|
||||
|
||||
"dtsRollup": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
2
packages/api-extractor/src/api/test/test-data/config-lookup3/index.d.ts
vendored
Normal file
2
packages/api-extractor/src/api/test/test-data/config-lookup3/index.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/* eslint-disable unicorn/no-empty-file */
|
||||
// empty file
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "config-lookup3",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
||||
|
||||
"mainEntryPointFilePath": "<projectFolder>/index.d.ts",
|
||||
|
||||
"apiReport": {
|
||||
"enabled": true
|
||||
},
|
||||
|
||||
"docModel": {
|
||||
"enabled": true
|
||||
},
|
||||
|
||||
"dtsRollup": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
2
packages/api-extractor/src/api/test/test-data/config-lookup3/src/test/index.d.ts
vendored
Normal file
2
packages/api-extractor/src/api/test/test-data/config-lookup3/src/test/index.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/* eslint-disable unicorn/no-empty-file */
|
||||
// empty file
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/tsconfig",
|
||||
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"rootDir": "src",
|
||||
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"experimentalDecorators": true,
|
||||
"strictNullChecks": true,
|
||||
"noUnusedLocals": true,
|
||||
"types": ["heft-jest", "node"],
|
||||
|
||||
"module": "commonjs",
|
||||
"target": "es2017",
|
||||
"lib": ["es2017"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
||||
"exclude": ["node_modules", "lib"]
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/tsconfig",
|
||||
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"rootDir": "src",
|
||||
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"experimentalDecorators": true,
|
||||
"strictNullChecks": true,
|
||||
"noUnusedLocals": true,
|
||||
"types": ["heft-jest", "node"],
|
||||
|
||||
"module": "commonjs",
|
||||
"target": "es2017",
|
||||
"lib": ["es2017"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
||||
"exclude": ["node_modules", "lib"]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
||||
|
||||
"mainEntryPointFilePath": "<projectFolder>/index.d.ts",
|
||||
|
||||
"apiReport": {
|
||||
"enabled": true
|
||||
},
|
||||
|
||||
"docModel": {
|
||||
"enabled": true
|
||||
},
|
||||
|
||||
"dtsRollup": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
7
packages/api-extractor/src/api/test/test-data/custom-tsdoc-tags/index.d.ts
vendored
Normal file
7
packages/api-extractor/src/api/test/test-data/custom-tsdoc-tags/index.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface,tsdoc/syntax */
|
||||
/**
|
||||
* @block
|
||||
* @inline test
|
||||
* @modifier
|
||||
*/
|
||||
interface CustomTagsTestInterface {}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "config-lookup1",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/tsconfig",
|
||||
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"rootDir": "src",
|
||||
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"experimentalDecorators": true,
|
||||
"strictNullChecks": true,
|
||||
"noUnusedLocals": true,
|
||||
"types": ["heft-jest", "node"],
|
||||
|
||||
"module": "commonjs",
|
||||
"target": "es2017",
|
||||
"lib": ["es2017"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
||||
"exclude": ["node_modules", "lib"]
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
|
||||
"extends": ["../../../../../extends/tsdoc-base.json"],
|
||||
"tagDefinitions": [
|
||||
{
|
||||
"tagName": "@block",
|
||||
"syntaxKind": "block"
|
||||
},
|
||||
{
|
||||
"tagName": "@inline",
|
||||
"syntaxKind": "inline",
|
||||
"allowMultiple": true
|
||||
},
|
||||
{
|
||||
"tagName": "@modifier",
|
||||
"syntaxKind": "modifier"
|
||||
}
|
||||
],
|
||||
"supportForTags": {
|
||||
"@block": true,
|
||||
"@inline": true,
|
||||
"@modifier": false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user