UNPKG

@microsoft/api-extractor

Version:

Validatation, documentation, and auditing for the exported API of a TypeScript package

243 lines (241 loc) 11.8 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); var os = require("os"); var path = require("path"); var ts = require("typescript"); var ApiItem_1 = require("../definitions/ApiItem"); var ApiItemVisitor_1 = require("../ApiItemVisitor"); var ApiMember_1 = require("../definitions/ApiMember"); var ApiDocumentation_1 = require("../definitions/ApiDocumentation"); var JsonFile_1 = require("../JsonFile"); var ApiJsonFile_1 = require("./ApiJsonFile"); /** * For a library such as "example-package", ApiFileGenerator generates the "example-package.api.ts" * report which is used to detect API changes. The output is pseudocode whose syntax is similar * but not identical to a "*.d.ts" typings file. The output file is designed to be committed to * Git with a branch policy that will trigger an API review workflow whenever the file contents * have changed. For example, the API file indicates *whether* a class has been documented, * but it does not include the documentation text (since minor text changes should not require * an API review). */ var ApiJsonGenerator = (function (_super) { __extends(ApiJsonGenerator, _super); function ApiJsonGenerator() { var _this = _super !== null && _super.apply(this, arguments) || this; // Only allow @public _this.apiTagsToSkip = [ ApiDocumentation_1.ApiTag.Alpha, ApiDocumentation_1.ApiTag.Beta, ApiDocumentation_1.ApiTag.Internal ]; _this.jsonOutput = {}; return _this; } ApiJsonGenerator.prototype.writeJsonFile = function (reportFilename, extractor) { this.visit(extractor.package, this.jsonOutput); // Write the output before validating the schema, so we can debug it JsonFile_1.default.saveJsonFile(reportFilename, this.jsonOutput); // Validate that the output conforms to our JSON schema var apiJsonSchema = JsonFile_1.default.loadJsonFile(path.join(__dirname, '../schemas/api-json-schema.json')); JsonFile_1.default.validateSchema(this.jsonOutput, apiJsonSchema, function (errorDetail) { var errorMessage = "ApiJsonGenerator validation error - output does not conform to api-json-schema.json:" + os.EOL + reportFilename + os.EOL + errorDetail; console.log(os.EOL + 'ERROR: ' + errorMessage + os.EOL + os.EOL); throw new Error(errorMessage); }); }; ApiJsonGenerator.prototype.visitApiStructuredType = function (apiStructuredType, refObject) { if (!apiStructuredType.supportedName) { return; } var kind = apiStructuredType.kind === ApiItem_1.ApiItemKind.Class ? ApiJsonFile_1.default.convertKindToJson(ApiItem_1.ApiItemKind.Class) : apiStructuredType.kind === ApiItem_1.ApiItemKind.Interface ? ApiJsonFile_1.default.convertKindToJson(ApiItem_1.ApiItemKind.Interface) : ''; var structureNode = { kind: kind, extends: apiStructuredType.extends || '', implements: apiStructuredType.implements || '', typeParameters: apiStructuredType.typeParameters || [], deprecatedMessage: apiStructuredType.documentation.deprecatedMessage || [], summary: apiStructuredType.documentation.summary || [], remarks: apiStructuredType.documentation.remarks || [], isBeta: apiStructuredType.documentation.apiTag === ApiDocumentation_1.ApiTag.Beta }; refObject[apiStructuredType.name] = structureNode; ApiJsonGenerator._methodCounter = 0; var members = apiStructuredType.getSortedMemberItems(); if (members && members.length) { var membersNode = {}; structureNode[ApiJsonGenerator._MEMBERS_KEY] = membersNode; for (var _i = 0, members_1 = members; _i < members_1.length; _i++) { var apiItem = members_1[_i]; this.visit(apiItem, membersNode); } } }; ApiJsonGenerator.prototype.visitApiEnum = function (apiEnum, refObject) { if (!apiEnum.supportedName) { return; } var valuesNode = {}; var enumNode = { kind: ApiJsonFile_1.default.convertKindToJson(apiEnum.kind), values: valuesNode, deprecatedMessage: apiEnum.documentation.deprecatedMessage || [], summary: apiEnum.documentation.summary || [], remarks: apiEnum.documentation.remarks || [], isBeta: apiEnum.documentation.apiTag === ApiDocumentation_1.ApiTag.Beta }; refObject[apiEnum.name] = enumNode; for (var _i = 0, _a = apiEnum.getSortedMemberItems(); _i < _a.length; _i++) { var apiItem = _a[_i]; this.visit(apiItem, valuesNode); } }; ApiJsonGenerator.prototype.visitApiEnumValue = function (apiEnumValue, refObject) { if (!apiEnumValue.supportedName) { return; } var declaration = apiEnumValue.getDeclaration(); var firstToken = declaration ? declaration.getFirstToken() : undefined; var lastToken = declaration ? declaration.getLastToken() : undefined; var value = lastToken && lastToken !== firstToken ? lastToken.getText() : ''; refObject[apiEnumValue.name] = { kind: ApiJsonFile_1.default.convertKindToJson(apiEnumValue.kind), value: value, deprecatedMessage: apiEnumValue.documentation.deprecatedMessage || [], summary: apiEnumValue.documentation.summary || [], remarks: apiEnumValue.documentation.remarks || [], isBeta: apiEnumValue.documentation.apiTag === ApiDocumentation_1.ApiTag.Beta }; }; ApiJsonGenerator.prototype.visitApiFunction = function (apiFunction, refObject) { if (!apiFunction.supportedName) { return; } for (var _i = 0, _a = apiFunction.params; _i < _a.length; _i++) { var param = _a[_i]; this.visitApiParam(param, apiFunction.documentation.parameters[param.name]); } var returnValueNode = { type: apiFunction.returnType, description: apiFunction.documentation.returnsMessage }; var newNode = { kind: ApiJsonFile_1.default.convertKindToJson(apiFunction.kind), returnValue: returnValueNode, parameters: apiFunction.documentation.parameters, deprecatedMessage: apiFunction.documentation.deprecatedMessage || [], summary: apiFunction.documentation.summary || [], remarks: apiFunction.documentation.remarks || [], isBeta: apiFunction.documentation.apiTag === ApiDocumentation_1.ApiTag.Beta }; refObject[apiFunction.name] = newNode; }; ApiJsonGenerator.prototype.visitApiPackage = function (apiPackage, refObject) { /* tslint:disable:no-string-literal */ refObject['kind'] = ApiJsonFile_1.default.convertKindToJson(apiPackage.kind); refObject['summary'] = apiPackage.documentation.summary; refObject['remarks'] = apiPackage.documentation.remarks; /* tslint:enable:no-string-literal */ var membersNode = {}; refObject[ApiJsonGenerator._EXPORTS_KEY] = membersNode; for (var _i = 0, _a = apiPackage.getSortedMemberItems(); _i < _a.length; _i++) { var apiItem = _a[_i]; this.visit(apiItem, membersNode); } }; ApiJsonGenerator.prototype.visitApiMember = function (apiMember, refObject) { if (!apiMember.supportedName) { return; } refObject[apiMember.name] = 'apiMember-' + apiMember.getDeclaration().kind; }; ApiJsonGenerator.prototype.visitApiProperty = function (apiProperty, refObject) { if (!apiProperty.supportedName) { return; } if (apiProperty.getDeclaration().kind === ts.SyntaxKind.SetAccessor) { return; } var newNode = { kind: ApiJsonFile_1.default.convertKindToJson(apiProperty.kind), isOptional: !!apiProperty.isOptional, isReadOnly: !!apiProperty.isReadOnly, isStatic: !!apiProperty.isStatic, type: apiProperty.type, deprecatedMessage: apiProperty.documentation.deprecatedMessage || [], summary: apiProperty.documentation.summary || [], remarks: apiProperty.documentation.remarks || [], isBeta: apiProperty.documentation.apiTag === ApiDocumentation_1.ApiTag.Beta }; refObject[apiProperty.name] = newNode; }; ApiJsonGenerator.prototype.visitApiMethod = function (apiMethod, refObject) { if (!apiMethod.supportedName) { return; } for (var _i = 0, _a = apiMethod.params; _i < _a.length; _i++) { var param = _a[_i]; this.visitApiParam(param, apiMethod.documentation.parameters[param.name]); } var newNode; if (apiMethod.name === '__constructor') { newNode = { kind: ApiJsonFile_1.default.convertKindToJson(ApiItem_1.ApiItemKind.Constructor), signature: apiMethod.getDeclarationLine(), parameters: apiMethod.documentation.parameters, deprecatedMessage: apiMethod.documentation.deprecatedMessage || [], summary: apiMethod.documentation.summary || [], remarks: apiMethod.documentation.remarks || [] }; } else { var returnValueNode = { type: apiMethod.returnType, description: apiMethod.documentation.returnsMessage }; newNode = { kind: ApiJsonFile_1.default.convertKindToJson(apiMethod.kind), signature: apiMethod.getDeclarationLine(), accessModifier: apiMethod.accessModifier ? ApiMember_1.AccessModifier[apiMethod.accessModifier].toLowerCase() : '', isOptional: !!apiMethod.isOptional, isStatic: !!apiMethod.isStatic, returnValue: returnValueNode, parameters: apiMethod.documentation.parameters, deprecatedMessage: apiMethod.documentation.deprecatedMessage || [], summary: apiMethod.documentation.summary || [], remarks: apiMethod.documentation.remarks || [], isBeta: apiMethod.documentation.apiTag === ApiDocumentation_1.ApiTag.Beta }; } refObject[apiMethod.name] = newNode; }; ApiJsonGenerator.prototype.visitApiParam = function (apiParam, refObject) { if (!apiParam.supportedName) { return; } if (refObject) { refObject.isOptional = apiParam.isOptional; refObject.isSpread = apiParam.isSpread; refObject.type = apiParam.type; } }; return ApiJsonGenerator; }(ApiItemVisitor_1.default)); ApiJsonGenerator._methodCounter = 0; ApiJsonGenerator._MEMBERS_KEY = 'members'; ApiJsonGenerator._EXPORTS_KEY = 'exports'; exports.default = ApiJsonGenerator; //# sourceMappingURL=ApiJsonGenerator.js.map