Socket
Socket
Sign inDemoInstall

@microsoft/api-extractor

Package Overview
Dependencies
Maintainers
2
Versions
487
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@microsoft/api-extractor - npm Package Compare versions

Comparing version 4.0.1 to 4.1.0

lib/ast/AstModule.d.ts

26

CHANGELOG.json

@@ -5,2 +5,28 @@ {

{
"version": "4.1.0",
"tag": "@microsoft/api-extractor_v4.1.0",
"date": "Fri, 20 Oct 2017 19:57:12 GMT",
"comments": {
"patch": [
{
"author": "pgonzal <pgonzal@users.noreply.github.com>",
"commit": "3c4f7aeb43999a968da41a8a2a2acbc3410f4ae9",
"comment": "Fixed an issue where properties were sometimes marked as readonly; a remark is automatically generated for classes with internal constructors"
}
],
"minor": [
{
"author": "pgonzal <pgonzal@users.noreply.github.com>",
"commit": "e37c63a2810a22957806bfe6a607b6c925244b7a",
"comment": "Add policies.namespaceSupport option to API Extractor config"
}
],
"dependency": [
{
"comment": "Updating dependency \"@microsoft/node-core-library\" from `~0.3.6` to `~0.3.7`"
}
]
}
},
{
"version": "4.0.1",

@@ -7,0 +33,0 @@ "tag": "@microsoft/api-extractor_v4.0.1",

13

CHANGELOG.md
# Change Log - @microsoft/api-extractor
This log was last generated on Fri, 20 Oct 2017 01:52:54 GMT and should not be manually modified.
This log was last generated on Fri, 20 Oct 2017 19:57:12 GMT and should not be manually modified.
## 4.1.0
Fri, 20 Oct 2017 19:57:12 GMT
### Minor changes
- Add policies.namespaceSupport option to API Extractor config
### Patches
- Fixed an issue where properties were sometimes marked as readonly; a remark is automatically generated for classes with internal constructors
## 4.0.1

@@ -6,0 +17,0 @@ Fri, 20 Oct 2017 01:52:54 GMT

@@ -684,3 +684,11 @@ {

"oneOf": [
{ "$ref": "#/definitions/moduleVariableApiItem" }
// Conservative mode
{ "$ref": "#/definitions/moduleVariableApiItem" },
// Permissive mode
{ "$ref": "#/definitions/classApiItem" },
{ "$ref": "#/definitions/interfaceApiItem" },
{ "$ref": "#/definitions/namespaceApiItem" },
{ "$ref": "#/definitions/enumApiItem" },
{ "$ref": "#/definitions/functionApiItem" }
]

@@ -687,0 +695,0 @@ }

@@ -99,3 +99,3 @@ import { IDocElement } from '../markup/OldMarkup';

/**
* kind of DocItem. Ex: 'class', 'Enum', 'Function', etc.
* kind of item: 'class', 'enum', 'function', etc.
*/

@@ -288,2 +288,16 @@ kind: string;

/**
* IApiInterface represents an exported interface.
* @alpha
*/
export interface IApiNamespace extends IApiBaseDefinition {
/**
* {@inheritdoc IApiBaseDefinition.kind}
*/
kind: 'namespace';
/**
* A mapping from the name of a member API to its ApiMember
*/
exports: IApiNameMap<ApiItem>;
}
/**
* IApiPackage is an object contaning the exported

@@ -328,3 +342,3 @@ * definions of this API package. The exports can include:

*/
export declare type ApiItem = IApiProperty | ApiMember | IApiFunction | IApiConstructor | IApiClass | IApiEnum | IApiEnumMember | IApiInterface | IApiPackage;
export declare type ApiItem = IApiProperty | ApiMember | IApiFunction | IApiConstructor | IApiClass | IApiEnum | IApiEnumMember | IApiInterface | IApiNamespace | IApiPackage;
/**

@@ -331,0 +345,0 @@ * Describes a return type and description of the return type

2

lib/ast/AstItemContainer.d.ts
import AstItem, { IAstItemOptions } from './AstItem';
/**
* This is an abstract base class for AstPackage, AstEnum, and AstStructuredType,
* This is an abstract base class for AstModule, AstEnum, and AstStructuredType,
* which all act as containers for other AstItem definitions.

@@ -5,0 +5,0 @@ */

@@ -7,3 +7,3 @@ "use strict";

/**
* This is an abstract base class for AstPackage, AstEnum, and AstStructuredType,
* This is an abstract base class for AstModule, AstEnum, and AstStructuredType,
* which all act as containers for other AstItem definitions.

@@ -10,0 +10,0 @@ */

@@ -14,9 +14,4 @@ import { IAstItemOptions } from './AstItem';

readonly params: AstParameter[];
private readonly _isConstructor;
constructor(options: IAstItemOptions);
/**
* Returns true if this member represents a class constructor.
*/
readonly isConstructor: boolean;
protected onCompleteInitialization(): void;
}

@@ -21,3 +21,9 @@ "use strict";

super(options);
this.kind = AstItem_1.AstItemKind.Method;
// tslint:disable-next-line:no-bitwise
if ((options.declarationSymbol.flags & ts.SymbolFlags.Constructor) !== 0) {
this.kind = AstItem_1.AstItemKind.Constructor;
}
else {
this.kind = AstItem_1.AstItemKind.Method;
}
const methodDeclaration = options.declaration;

@@ -39,6 +45,4 @@ // Parameters

}
// tslint:disable-next-line:no-bitwise
this._isConstructor = (options.declarationSymbol.flags & ts.SymbolFlags.Constructor) !== 0;
// Return type
if (!this.isConstructor) {
if (this.kind !== AstItem_1.AstItemKind.Constructor) {
if (methodDeclaration.type) {

@@ -53,8 +57,2 @@ this.returnType = methodDeclaration.type.getText();

}
/**
* Returns true if this member represents a class constructor.
*/
get isConstructor() {
return this._isConstructor;
}
onCompleteInitialization() {

@@ -65,3 +63,3 @@ super.onCompleteInitialization();

// Generally class constructors have uninteresting documentation.
if (this.isConstructor) {
if (this.kind === AstItem_1.AstItemKind.Constructor) {
if (this.documentation.summary.length === 0) {

@@ -68,0 +66,0 @@ this.documentation.summary.push({

import { IAstItemOptions } from './AstItem';
import AstItemContainer from './AstItemContainer';
import AstModule from './AstModule';
/**

@@ -16,5 +16,7 @@ * This class is part of the AstItem abstract syntax tree. It represents exports of

*/
export default class AstNamespace extends AstItemContainer {
export default class AstNamespace extends AstModule {
private _exportedNormalizedSymbols;
constructor(options: IAstItemOptions);
private _processConservativeMembers(exportSymbols);
private _processPermissiveMembers(exportSymbols);
}

@@ -9,3 +9,3 @@ "use strict";

const AstItem_1 = require("./AstItem");
const AstItemContainer_1 = require("./AstItemContainer");
const AstModule_1 = require("./AstModule");
const allowedTypes = ['string', 'number', 'boolean'];

@@ -25,3 +25,3 @@ /**

*/
class AstNamespace extends AstItemContainer_1.default {
class AstNamespace extends AstModule_1.default {
constructor(options) {

@@ -34,65 +34,80 @@ super(options);

if (exportSymbols) {
for (const exportSymbol of exportSymbols) {
const followedSymbol = this.followAliases(exportSymbol);
if (!followedSymbol.declarations) {
// This is an API Extractor bug, but it could happen e.g. if we upgrade to a new
// version of the TypeScript compiler that introduces new AST variations that we
// haven't tested before.
this.reportWarning(`The definition "${exportSymbol.name}" has no declarations`);
continue;
}
if (!(followedSymbol.flags === ts.SymbolFlags.BlockScopedVariable)) {
this.reportWarning(`Unsupported export "${exportSymbol.name}" ` +
'Currently the "namespace" block only supports constant variables.');
continue;
}
// Since we are imposing that the items within a namespace be
// const properties we are only taking the first declaration.
// If we decide to add support for other types within a namespace
// we will have for evaluate each declaration.
const declaration = followedSymbol.getDeclarations()[0];
if (declaration.parent.flags !== ts.NodeFlags.Const) {
this.reportWarning(`Export "${exportSymbol.name}" is missing the "const" ` +
'modifier. Currently the "namespace" block only supports constant variables.');
continue;
}
const propertySignature = declaration;
if (!propertySignature.type || allowedTypes.indexOf(propertySignature.type.getText()) < 0) {
this.reportWarning(`Export "${exportSymbol.name}" must specify and be of type` +
'"string", "number" or "boolean"');
continue;
}
if (!propertySignature.initializer) {
this.reportWarning(`Export "${exportSymbol.name}" must have an initialized value`);
continue;
}
// Typescript's VariableDeclaration AST nodes have an VariableDeclarationList parent,
// and the VariableDeclarationList exists within a VariableStatement, which is where
// the JSDoc comment Node can be found.
// If there is no parent or grandparent of this VariableDeclaration then
// we do not know how to obtain the JSDoc comment.
let jsdocNode;
if (!declaration.parent || !declaration.parent.parent ||
declaration.parent.parent.kind !== ts.SyntaxKind.VariableStatement) {
this.reportWarning(`Unable to locate the documentation node for "${exportSymbol.name}"; `
+ `this may be an API Extractor bug`);
}
else {
jsdocNode = declaration.parent.parent;
}
const exportMemberOptions = {
context: this.context,
declaration,
declarationSymbol: followedSymbol,
jsdocNode: jsdocNode,
exportSymbol
};
this.addMemberItem(new AstModuleVariable_1.default(exportMemberOptions));
this._exportedNormalizedSymbols.push({
exportedName: exportSymbol.name,
followedSymbol: followedSymbol
});
if (this.context.policies.namespaceSupport === 'conservative') {
this._processConservativeMembers(exportSymbols);
}
else {
this._processPermissiveMembers(exportSymbols);
}
}
}
// Used when policies.namespaceSupport=conservative
_processConservativeMembers(exportSymbols) {
for (const exportSymbol of exportSymbols) {
const followedSymbol = this.followAliases(exportSymbol);
if (!followedSymbol.declarations) {
// This is an API Extractor bug, but it could happen e.g. if we upgrade to a new
// version of the TypeScript compiler that introduces new AST variations that we
// haven't tested before.
this.reportWarning(`The definition "${exportSymbol.name}" has no declarations`);
continue;
}
if (!(followedSymbol.flags === ts.SymbolFlags.BlockScopedVariable)) {
this.reportWarning(`Unsupported export "${exportSymbol.name}" ` +
'Currently the "namespace" block only supports constant variables.');
continue;
}
// Since we are imposing that the items within a namespace be
// const properties we are only taking the first declaration.
// If we decide to add support for other types within a namespace
// we will have for evaluate each declaration.
const declaration = followedSymbol.getDeclarations()[0];
if (declaration.parent.flags !== ts.NodeFlags.Const) {
this.reportWarning(`Export "${exportSymbol.name}" is missing the "const" ` +
'modifier. Currently the "namespace" block only supports constant variables.');
continue;
}
const propertySignature = declaration;
if (!propertySignature.type || allowedTypes.indexOf(propertySignature.type.getText()) < 0) {
this.reportWarning(`Export "${exportSymbol.name}" must specify and be of type` +
'"string", "number" or "boolean"');
continue;
}
if (!propertySignature.initializer) {
this.reportWarning(`Export "${exportSymbol.name}" must have an initialized value`);
continue;
}
// Typescript's VariableDeclaration AST nodes have an VariableDeclarationList parent,
// and the VariableDeclarationList exists within a VariableStatement, which is where
// the JSDoc comment Node can be found.
// If there is no parent or grandparent of this VariableDeclaration then
// we do not know how to obtain the JSDoc comment.
let jsdocNode;
if (!declaration.parent || !declaration.parent.parent ||
declaration.parent.parent.kind !== ts.SyntaxKind.VariableStatement) {
this.reportWarning(`Unable to locate the documentation node for "${exportSymbol.name}"; `
+ `this may be an API Extractor bug`);
}
else {
jsdocNode = declaration.parent.parent;
}
const exportMemberOptions = {
context: this.context,
declaration,
declarationSymbol: followedSymbol,
jsdocNode: jsdocNode,
exportSymbol
};
this.addMemberItem(new AstModuleVariable_1.default(exportMemberOptions));
this._exportedNormalizedSymbols.push({
exportedName: exportSymbol.name,
followedSymbol: followedSymbol
});
}
}
// Used when policies.namespaceSupport=permissive
_processPermissiveMembers(exportSymbols) {
for (const exportSymbol of exportSymbols) {
this.processModuleExport(exportSymbol);
}
}
}

@@ -99,0 +114,0 @@ exports.default = AstNamespace;

import * as ts from 'typescript';
import { ExtractorContext } from '../ExtractorContext';
import AstItemContainer from './AstItemContainer';
import AstModule from './AstModule';
/**

@@ -8,3 +8,3 @@ * This class is part of the AstItem abstract syntax tree. It represents the top-level

*/
export default class AstPackage extends AstItemContainer {
export default class AstPackage extends AstModule {
private _exportedNormalizedSymbols;

@@ -11,0 +11,0 @@ private static _getOptions(context, rootFile);

@@ -7,8 +7,4 @@ "use strict";

const ts = require("typescript");
const AstStructuredType_1 = require("./AstStructuredType");
const AstEnum_1 = require("./AstEnum");
const AstFunction_1 = require("./AstFunction");
const AstItem_1 = require("./AstItem");
const AstItemContainer_1 = require("./AstItemContainer");
const AstNamespace_1 = require("./AstNamespace");
const AstModule_1 = require("./AstModule");
const TypeScriptHelpers_1 = require("../TypeScriptHelpers");

@@ -19,3 +15,3 @@ /**

*/
class AstPackage extends AstItemContainer_1.default {
class AstPackage extends AstModule_1.default {
constructor(context, rootFile) {

@@ -30,34 +26,4 @@ super(AstPackage._getOptions(context, rootFile));

for (const exportSymbol of exportSymbols) {
this.processModuleExport(exportSymbol);
const followedSymbol = this.followAliases(exportSymbol);
if (!followedSymbol.declarations) {
// This is an API Extractor bug, but it could happen e.g. if we upgrade to a new
// version of the TypeScript compiler that introduces new AST variations that we
// haven't tested before.
this.reportWarning(`Definition with no declarations: ${exportSymbol.name}`);
continue;
}
for (const declaration of followedSymbol.declarations) {
const options = {
context: this.context,
declaration,
declarationSymbol: followedSymbol,
jsdocNode: declaration,
exportSymbol
};
if (followedSymbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Interface)) {
this.addMemberItem(new AstStructuredType_1.default(options));
}
else if (followedSymbol.flags & ts.SymbolFlags.ValueModule) {
this.addMemberItem(new AstNamespace_1.default(options));
}
else if (followedSymbol.flags & ts.SymbolFlags.Function) {
this.addMemberItem(new AstFunction_1.default(options));
}
else if (followedSymbol.flags & ts.SymbolFlags.Enum) {
this.addMemberItem(new AstEnum_1.default(options));
}
else {
this.reportWarning(`Unsupported export: ${exportSymbol.name}`);
}
}
this._exportedNormalizedSymbols.push({

@@ -64,0 +30,0 @@ exportedName: exportSymbol.name,

@@ -5,2 +5,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const ts = require("typescript");
const AstItem_1 = require("./AstItem");

@@ -16,6 +17,3 @@ const AstMember_1 = require("./AstMember");

this.kind = AstItem_1.AstItemKind.Property;
if (this.documentation.hasReadOnlyTag) {
this.isReadOnly = true;
}
const declaration = options.declaration; /* tslint:disable-line:no-any */
const declaration = options.declaration;
if (declaration.type) {

@@ -28,2 +26,13 @@ this.type = declaration.type.getText();

}
if (this.documentation.hasReadOnlyTag) {
this.isReadOnly = true;
}
else {
// Check for a readonly modifier
for (const modifier of declaration.modifiers || []) {
if (modifier.kind === ts.SyntaxKind.ReadonlyKeyword) {
this.isReadOnly = true;
}
}
}
}

@@ -30,0 +39,0 @@ getDeclarationLine() {

@@ -35,3 +35,4 @@ import * as ts from 'typescript';

getDeclarationLine(): string;
protected onCompleteInitialization(): void;
private _processMember(memberSymbol, memberDeclaration);
}

@@ -7,2 +7,3 @@ "use strict";

const ts = require("typescript");
const ReleaseTag_1 = require("../aedoc/ReleaseTag");
const AstMethod_1 = require("./AstMethod");

@@ -128,2 +129,20 @@ const AstProperty_1 = require("./AstProperty");

}
onCompleteInitialization() {
super.onCompleteInitialization();
// Is the constructor internal?
for (const member of this.getSortedMemberItems()) {
if (member.kind === AstItem_1.AstItemKind.Constructor) {
if (member.documentation.releaseTag === ReleaseTag_1.ReleaseTag.Internal) {
// Add a boilerplate notice for classes with internal constructors
this.documentation.remarks.unshift({
kind: 'textDocElement',
value: `The constructor for this class is marked as internal. Third-party code`
+ ` should not extend subclasses of the ${this.name} class or instantiate it directly.`
}, {
kind: 'paragraphDocElement'
});
}
}
}
}
_processMember(memberSymbol, memberDeclaration) {

@@ -130,0 +149,0 @@ if (memberDeclaration.modifiers) {

@@ -11,3 +11,3 @@ "use strict";

const Extractor_1 = require("../extractor/Extractor");
const AE_CONFIG_FILENAME = 'api-extractor-config.json';
const AE_CONFIG_FILENAME = 'api-extractor.json';
class RunAction extends ts_command_line_1.CommandLineAction {

@@ -14,0 +14,0 @@ constructor(parser) {

@@ -261,2 +261,3 @@ "use strict";

case AstItem_1.AstItemKind.Method:
case AstItem_1.AstItemKind.Constructor:
documentation.parameters = resolvedAstItem.params;

@@ -263,0 +264,0 @@ documentation.returnsMessage = resolvedAstItem.returnsMessage;

@@ -81,3 +81,4 @@ "use strict";

entryPointFile: path.resolve(this._absoluteRootFolder, projectConfig.entryPointSourceFile),
logger: this._logger
logger: this._logger,
policies: this._config.policies
});

@@ -149,4 +150,4 @@ for (const externalJsonFileFolder of projectConfig.externalJsonFileFolders) {

*/
Extractor.jsonSchema = node_core_library_1.JsonSchema.fromFile(path.join(__dirname, './api-extractor-config.schema.json'));
Extractor._defaultConfig = node_core_library_1.JsonFile.load(path.join(__dirname, './api-extractor-config-default.json'));
Extractor.jsonSchema = node_core_library_1.JsonSchema.fromFile(path.join(__dirname, './api-extractor.schema.json'));
Extractor._defaultConfig = node_core_library_1.JsonFile.load(path.join(__dirname, './api-extractor-defaults.json'));
Extractor._defaultLogger = {

@@ -153,0 +154,0 @@ logVerbose: (message) => console.log('(Verbose) ' + message),

@@ -61,2 +61,17 @@ /**

/**
* These policies determine how API Extractor validates various best practices for API design.
*
* @public
*/
export interface IExtractorPoliciesConfig {
/**
* Controls how API Extractor treats the TypeScript namespace keyword:
*
* conservative - (the default) namespaces may only be used to represent tables of constants
*
* permissive - arbitrary nesting of namespaces is allowed
*/
namespaceSupport: 'conservative' | 'permissive';
}
/**
* Configures how the API review files (*.api.ts) will be generated.

@@ -130,2 +145,6 @@ *

/**
* {@inheritdoc IExtractorPoliciesConfig}
*/
policies?: IExtractorPoliciesConfig;
/**
* {@inheritdoc IExtractorProjectConfig}

@@ -132,0 +151,0 @@ */

@@ -6,2 +6,3 @@ import * as ts from 'typescript';

import { ILogger } from './extractor/ILogger';
import { IExtractorPoliciesConfig } from './extractor/IExtractorConfig';
/**

@@ -27,2 +28,3 @@ * Options for ExtractorContext constructor.

logger: ILogger;
policies: IExtractorPoliciesConfig;
}

@@ -43,2 +45,3 @@ /**

readonly packageJsonLookup: PackageJsonLookup;
readonly policies: IExtractorPoliciesConfig;
private _packageName;

@@ -45,0 +48,0 @@ private _packageFolder;

@@ -18,2 +18,3 @@ "use strict";

this.packageJsonLookup = new node_core_library_1.PackageJsonLookup();
this.policies = options.policies;
this._packageFolder = this.packageJsonLookup.tryGetPackageFolder(options.entryPointFile);

@@ -20,0 +21,0 @@ this._packageName = this.packageJsonLookup.getPackageName(this._packageFolder);

export { default as ExternalApiHelper } from './ExternalApiHelper';
export { Extractor, IAnalyzeProjectOptions, IExtractorOptions } from './extractor/Extractor';
export { IExtractorTsconfigCompilerConfig, IExtractorRuntimeCompilerConfig, IExtractorProjectConfig, IExtractorApiReviewFileConfig, IExtractorApiJsonFileConfig, IExtractorConfig } from './extractor/IExtractorConfig';
export { IExtractorTsconfigCompilerConfig, IExtractorRuntimeCompilerConfig, IExtractorProjectConfig, IExtractorPoliciesConfig, IExtractorApiReviewFileConfig, IExtractorApiJsonFileConfig, IExtractorConfig } from './extractor/IExtractorConfig';
export { ILogger } from './extractor/ILogger';

@@ -5,0 +5,0 @@ export * from './api/ApiItem';

{
"name": "@microsoft/api-extractor",
"version": "4.0.1",
"version": "4.1.0",
"description": "Validate, document, and review the exported API for a TypeScript library",

@@ -33,3 +33,3 @@ "keywords": [

"dependencies": {
"@microsoft/node-core-library": "~0.3.6",
"@microsoft/node-core-library": "~0.3.7",
"@microsoft/ts-command-line": "~2.1.0",

@@ -36,0 +36,0 @@ "@types/fs-extra": "0.0.37",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc