148 行
6.8 KiB
JavaScript
148 行
6.8 KiB
JavaScript
|
|
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
||
|
|
// See LICENSE in the project root for license information.
|
||
|
|
import { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference';
|
||
|
|
import { JsonFile, PackageJsonLookup } from '@rushstack/node-core-library';
|
||
|
|
import { TSDocConfiguration } from '@microsoft/tsdoc';
|
||
|
|
import { TSDocConfigFile } from '@microsoft/tsdoc-config';
|
||
|
|
import { ApiItem, ApiItemKind } from '../items/ApiItem';
|
||
|
|
import { ApiItemContainerMixin } from '../mixins/ApiItemContainerMixin';
|
||
|
|
import { ApiDocumentedItem } from '../items/ApiDocumentedItem';
|
||
|
|
import { ApiNameMixin } from '../mixins/ApiNameMixin';
|
||
|
|
import { DeserializerContext, ApiJsonSchemaVersion } from './DeserializerContext';
|
||
|
|
/**
|
||
|
|
* 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)) {
|
||
|
|
constructor(options) {
|
||
|
|
super(options);
|
||
|
|
this._tsdocConfiguration = options.tsdocConfiguration;
|
||
|
|
this._projectFolderUrl = options.projectFolderUrl;
|
||
|
|
}
|
||
|
|
/** @override */
|
||
|
|
static onDeserializeInto(options, context, jsonObject) {
|
||
|
|
super.onDeserializeInto(options, context, jsonObject);
|
||
|
|
options.projectFolderUrl = jsonObject.projectFolderUrl;
|
||
|
|
}
|
||
|
|
static loadFromJsonFile(apiJsonFilename) {
|
||
|
|
const jsonObject = JsonFile.load(apiJsonFilename);
|
||
|
|
if (!jsonObject || !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 = 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 = 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 = 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 = new TSDocConfiguration();
|
||
|
|
if (versionToDeserialize >= ApiJsonSchemaVersion.V_1004) {
|
||
|
|
const tsdocConfigFile = TSDocConfigFile.loadFromObject(jsonObject.metadata.tsdocConfig);
|
||
|
|
if (tsdocConfigFile.hasErrors) {
|
||
|
|
throw new Error(`Error loading ${apiJsonFilename}:\n` + tsdocConfigFile.getErrorSummary());
|
||
|
|
}
|
||
|
|
tsdocConfigFile.configureParser(tsdocConfiguration);
|
||
|
|
}
|
||
|
|
const context = new DeserializerContext({
|
||
|
|
apiJsonFilename,
|
||
|
|
toolPackage: jsonObject.metadata.toolPackage,
|
||
|
|
toolVersion: jsonObject.metadata.toolVersion,
|
||
|
|
versionToDeserialize: versionToDeserialize,
|
||
|
|
tsdocConfiguration
|
||
|
|
});
|
||
|
|
return ApiItem.deserialize(jsonObject, context);
|
||
|
|
}
|
||
|
|
/** @override */
|
||
|
|
get kind() {
|
||
|
|
return ApiItemKind.Package;
|
||
|
|
}
|
||
|
|
/** @override */
|
||
|
|
get containerKey() {
|
||
|
|
// No prefix needed, because ApiPackage is the only possible member of an ApiModel
|
||
|
|
return this.name;
|
||
|
|
}
|
||
|
|
get entryPoints() {
|
||
|
|
return this.members;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* 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.
|
||
|
|
*/
|
||
|
|
get tsdocConfiguration() {
|
||
|
|
return this._tsdocConfiguration;
|
||
|
|
}
|
||
|
|
get projectFolderUrl() {
|
||
|
|
return this._projectFolderUrl;
|
||
|
|
}
|
||
|
|
/** @override */
|
||
|
|
addMember(member) {
|
||
|
|
if (member.kind !== ApiItemKind.EntryPoint) {
|
||
|
|
throw new Error('Only items of type ApiEntryPoint may be added to an ApiPackage');
|
||
|
|
}
|
||
|
|
super.addMember(member);
|
||
|
|
}
|
||
|
|
findEntryPointsByPath(importPath) {
|
||
|
|
return this.findMembersByName(importPath);
|
||
|
|
}
|
||
|
|
saveToJsonFile(apiJsonFilename, options) {
|
||
|
|
if (!options) {
|
||
|
|
options = {};
|
||
|
|
}
|
||
|
|
const packageJson = PackageJsonLookup.loadOwnPackageJson(__dirname);
|
||
|
|
const tsdocConfigFile = TSDocConfigFile.loadFromParser(this.tsdocConfiguration);
|
||
|
|
const tsdocConfig = tsdocConfigFile.saveToObject();
|
||
|
|
const jsonObject = {
|
||
|
|
metadata: {
|
||
|
|
toolPackage: options.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: options.testMode ? '[test mode]' : options.toolVersion || packageJson.version,
|
||
|
|
schemaVersion: ApiJsonSchemaVersion.LATEST,
|
||
|
|
oldestForwardsCompatibleVersion: ApiJsonSchemaVersion.OLDEST_FORWARDS_COMPATIBLE,
|
||
|
|
tsdocConfig
|
||
|
|
}
|
||
|
|
};
|
||
|
|
if (this.projectFolderUrl) {
|
||
|
|
jsonObject.projectFolderUrl = this.projectFolderUrl;
|
||
|
|
}
|
||
|
|
this.serializeInto(jsonObject);
|
||
|
|
JsonFile.save(jsonObject, apiJsonFilename, options);
|
||
|
|
}
|
||
|
|
/** @beta @override */
|
||
|
|
buildCanonicalReference() {
|
||
|
|
return DeclarationReference.package(this.name);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//# sourceMappingURL=ApiPackage.js.map
|