mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-14 10:33:30 +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:
312
packages/api-extractor-model/src/model/ApiPackage.ts
Normal file
312
packages/api-extractor-model/src/model/ApiPackage.ts
Normal file
@@ -0,0 +1,312 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
import { TSDocConfiguration } from '@microsoft/tsdoc';
|
||||
import { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';
|
||||
import { TSDocConfigFile } from '@microsoft/tsdoc-config';
|
||||
import {
|
||||
JsonFile,
|
||||
type IJsonFileSaveOptions,
|
||||
PackageJsonLookup,
|
||||
type IPackageJson,
|
||||
type JsonObject,
|
||||
} from '@rushstack/node-core-library';
|
||||
import { ApiDocumentedItem, type IApiDocumentedItemOptions } from '../items/ApiDocumentedItem.js';
|
||||
import { ApiItem, ApiItemKind, type IApiItemJson } from '../items/ApiItem.js';
|
||||
import { ApiItemContainerMixin, type IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin.js';
|
||||
import { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin.js';
|
||||
import type { ApiEntryPoint } from './ApiEntryPoint.js';
|
||||
import { DeserializerContext, ApiJsonSchemaVersion } from './DeserializerContext.js';
|
||||
|
||||
/**
|
||||
* Constructor options for {@link ApiPackage}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface IApiPackageOptions
|
||||
extends IApiItemContainerMixinOptions,
|
||||
IApiNameMixinOptions,
|
||||
IApiDocumentedItemOptions {
|
||||
projectFolderUrl?: string | undefined;
|
||||
tsdocConfiguration: TSDocConfiguration;
|
||||
}
|
||||
|
||||
export interface IApiPackageMetadataJson {
|
||||
/**
|
||||
* To support forwards compatibility, the `oldestForwardsCompatibleVersion` field tracks the oldest schema version
|
||||
* whose corresponding deserializer could safely load this file.
|
||||
*
|
||||
* @remarks
|
||||
* Normally api-extractor-model should refuse to load a schema version that is newer than the latest version
|
||||
* that its deserializer understands. However, sometimes a schema change may merely introduce some new fields
|
||||
* without modifying or removing any existing fields. In this case, an older api-extractor-model library can
|
||||
* safely deserialize the newer version (by ignoring the extra fields that it doesn't recognize). The newer
|
||||
* serializer can use this field to communicate that.
|
||||
*
|
||||
* If present, the `oldestForwardsCompatibleVersion` must be less than or equal to
|
||||
* `IApiPackageMetadataJson.schemaVersion`.
|
||||
*/
|
||||
oldestForwardsCompatibleVersion?: ApiJsonSchemaVersion;
|
||||
|
||||
/**
|
||||
* The schema version for the .api.json file format. Used for determining whether the file format is
|
||||
* supported, and for backwards compatibility.
|
||||
*/
|
||||
schemaVersion: ApiJsonSchemaVersion;
|
||||
|
||||
/**
|
||||
* The NPM package name for the tool that wrote the *.api.json file.
|
||||
* For informational purposes only.
|
||||
*/
|
||||
toolPackage: string;
|
||||
|
||||
/**
|
||||
* The NPM package version for the tool that wrote the *.api.json file.
|
||||
* For informational purposes only.
|
||||
*/
|
||||
toolVersion: string;
|
||||
|
||||
/**
|
||||
* The TSDoc configuration that was used when analyzing the API for this package.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* The structure of this objet is defined by the `@microsoft/tsdoc-config` library.
|
||||
* Normally this configuration is loaded from the project's tsdoc.json file. It is stored
|
||||
* in the .api.json file so that doc comments can be parsed accurately when loading the file.
|
||||
*/
|
||||
tsdocConfig: JsonObject;
|
||||
}
|
||||
|
||||
export interface IApiPackageJson extends IApiItemJson {
|
||||
/**
|
||||
* A file header that stores metadata about the tool that wrote the *.api.json file.
|
||||
*/
|
||||
metadata: IApiPackageMetadataJson;
|
||||
|
||||
/**
|
||||
* 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. Provided via the
|
||||
* `api-extractor.json` config.
|
||||
*/
|
||||
projectFolderUrl?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for {@link ApiPackage.saveToJsonFile}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface IApiPackageSaveOptions extends IJsonFileSaveOptions {
|
||||
/**
|
||||
* Set to true only 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;
|
||||
|
||||
/**
|
||||
* Optionally specifies a value for the "toolPackage" field in the output .api.json data file;
|
||||
* otherwise, the value will be "api-extractor-model".
|
||||
*/
|
||||
toolPackage?: string;
|
||||
|
||||
/**
|
||||
* Optionally specifies a value for the "toolVersion" field in the output .api.json data file;
|
||||
* otherwise, the value will be the current version of the api-extractor-model package.
|
||||
*/
|
||||
toolVersion?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an NPM package containing API declarations.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of
|
||||
* API declarations.
|
||||
* @public
|
||||
*/
|
||||
export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumentedItem)) {
|
||||
private readonly _tsdocConfiguration: TSDocConfiguration;
|
||||
|
||||
private readonly _projectFolderUrl?: string | undefined;
|
||||
|
||||
public constructor(options: IApiPackageOptions) {
|
||||
super(options);
|
||||
|
||||
this._tsdocConfiguration = options.tsdocConfiguration;
|
||||
this._projectFolderUrl = options.projectFolderUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
public static override onDeserializeInto(
|
||||
options: Partial<IApiPackageOptions>,
|
||||
context: DeserializerContext,
|
||||
jsonObject: IApiPackageJson,
|
||||
): void {
|
||||
super.onDeserializeInto(options, context, jsonObject);
|
||||
|
||||
options.projectFolderUrl = jsonObject.projectFolderUrl;
|
||||
}
|
||||
|
||||
public static loadFromJsonFile(apiJsonFilename: string): ApiPackage {
|
||||
const jsonObject: IApiPackageJson = JsonFile.load(apiJsonFilename);
|
||||
|
||||
if (!jsonObject?.metadata || typeof jsonObject.metadata.schemaVersion !== 'number') {
|
||||
throw new Error(
|
||||
`Error loading ${apiJsonFilename}:` +
|
||||
`\nThe file format is not recognized; the "metadata.schemaVersion" field is missing or invalid`,
|
||||
);
|
||||
}
|
||||
|
||||
const schemaVersion: number = jsonObject.metadata.schemaVersion;
|
||||
|
||||
if (schemaVersion < ApiJsonSchemaVersion.OLDEST_SUPPORTED) {
|
||||
throw new Error(
|
||||
`Error loading ${apiJsonFilename}:` +
|
||||
`\nThe file format is version ${schemaVersion},` +
|
||||
` whereas ${ApiJsonSchemaVersion.OLDEST_SUPPORTED} is the oldest version supported by this tool`,
|
||||
);
|
||||
}
|
||||
|
||||
let oldestForwardsCompatibleVersion: number = schemaVersion;
|
||||
if (jsonObject.metadata.oldestForwardsCompatibleVersion) {
|
||||
// Sanity check
|
||||
if (jsonObject.metadata.oldestForwardsCompatibleVersion > schemaVersion) {
|
||||
throw new Error(
|
||||
`Error loading ${apiJsonFilename}:` +
|
||||
`\nInvalid file format; "oldestForwardsCompatibleVersion" cannot be newer than "schemaVersion"`,
|
||||
);
|
||||
}
|
||||
|
||||
oldestForwardsCompatibleVersion = jsonObject.metadata.oldestForwardsCompatibleVersion;
|
||||
}
|
||||
|
||||
let versionToDeserialize: number = schemaVersion;
|
||||
if (versionToDeserialize > ApiJsonSchemaVersion.LATEST) {
|
||||
// If the file format is too new, can we treat it as some earlier compatible version
|
||||
// as indicated by oldestForwardsCompatibleVersion?
|
||||
versionToDeserialize = Math.max(oldestForwardsCompatibleVersion, ApiJsonSchemaVersion.LATEST);
|
||||
|
||||
if (versionToDeserialize > ApiJsonSchemaVersion.LATEST) {
|
||||
// Nope, still too new
|
||||
throw new Error(
|
||||
`Error loading ${apiJsonFilename}:` +
|
||||
`\nThe file format version ${schemaVersion} was written by a newer release of` +
|
||||
` the api-extractor-model library; you may need to upgrade your software`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const tsdocConfiguration: TSDocConfiguration = new TSDocConfiguration();
|
||||
|
||||
if (versionToDeserialize >= ApiJsonSchemaVersion.V_1004) {
|
||||
const tsdocConfigFile: TSDocConfigFile = TSDocConfigFile.loadFromObject(jsonObject.metadata.tsdocConfig);
|
||||
if (tsdocConfigFile.hasErrors) {
|
||||
throw new Error(`Error loading ${apiJsonFilename}:\n` + tsdocConfigFile.getErrorSummary());
|
||||
}
|
||||
|
||||
tsdocConfigFile.configureParser(tsdocConfiguration);
|
||||
}
|
||||
|
||||
const context: DeserializerContext = new DeserializerContext({
|
||||
apiJsonFilename,
|
||||
toolPackage: jsonObject.metadata.toolPackage,
|
||||
toolVersion: jsonObject.metadata.toolVersion,
|
||||
versionToDeserialize,
|
||||
tsdocConfiguration,
|
||||
});
|
||||
|
||||
return ApiItem.deserialize(jsonObject, context) as ApiPackage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
public override get kind(): ApiItemKind {
|
||||
return ApiItemKind.Package;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
public override get containerKey(): string {
|
||||
// No prefix needed, because ApiPackage is the only possible member of an ApiModel
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public get entryPoints(): readonly ApiEntryPoint[] {
|
||||
return this.members as readonly ApiEntryPoint[];
|
||||
}
|
||||
|
||||
/**
|
||||
* The TSDoc configuration that was used when analyzing the API for this package.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Normally this configuration is loaded from the project's tsdoc.json file. It is stored
|
||||
* in the .api.json file so that doc comments can be parsed accurately when loading the file.
|
||||
*/
|
||||
public get tsdocConfiguration(): TSDocConfiguration {
|
||||
return this._tsdocConfiguration;
|
||||
}
|
||||
|
||||
public get projectFolderUrl(): string | undefined {
|
||||
return this._projectFolderUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
public override addMember(member: ApiEntryPoint): void {
|
||||
if (member.kind !== ApiItemKind.EntryPoint) {
|
||||
throw new Error('Only items of type ApiEntryPoint may be added to an ApiPackage');
|
||||
}
|
||||
|
||||
super.addMember(member);
|
||||
}
|
||||
|
||||
public findEntryPointsByPath(importPath: string): readonly ApiEntryPoint[] {
|
||||
return this.findMembersByName(importPath) as readonly ApiEntryPoint[];
|
||||
}
|
||||
|
||||
public saveToJsonFile(apiJsonFilename: string, options?: IApiPackageSaveOptions): void {
|
||||
const ioptions = options ?? {};
|
||||
|
||||
const packageJson: IPackageJson = PackageJsonLookup.loadOwnPackageJson(__dirname);
|
||||
|
||||
const tsdocConfigFile: TSDocConfigFile = TSDocConfigFile.loadFromParser(this.tsdocConfiguration);
|
||||
const tsdocConfig: JsonObject = tsdocConfigFile.saveToObject();
|
||||
|
||||
const jsonObject: IApiPackageJson = {
|
||||
metadata: {
|
||||
toolPackage: ioptions.toolPackage ?? packageJson.name,
|
||||
// In test mode, we don't write the real version, since that would cause spurious diffs whenever
|
||||
// the version is bumped. Instead we write a placeholder string.
|
||||
toolVersion: ioptions.testMode ? '[test mode]' : ioptions.toolVersion ?? packageJson.version,
|
||||
schemaVersion: ApiJsonSchemaVersion.LATEST,
|
||||
oldestForwardsCompatibleVersion: ApiJsonSchemaVersion.OLDEST_FORWARDS_COMPATIBLE,
|
||||
tsdocConfig,
|
||||
},
|
||||
} as IApiPackageJson;
|
||||
|
||||
if (this.projectFolderUrl) {
|
||||
jsonObject.projectFolderUrl = this.projectFolderUrl;
|
||||
}
|
||||
|
||||
this.serializeInto(jsonObject);
|
||||
JsonFile.save(jsonObject, apiJsonFilename, ioptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @beta @override
|
||||
*/
|
||||
public override buildCanonicalReference(): DeclarationReference {
|
||||
return DeclarationReference.package(this.name);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user