@microsoft/api-extractor
Advanced tools
Comparing version 1.1.11 to 1.1.12
@@ -5,2 +5,14 @@ { | ||
{ | ||
"version": "1.1.12", | ||
"tag": "@microsoft/api-extractor_v1.1.12", | ||
"date": "Thu, 16 Feb 2017 18:56:57 GMT", | ||
"comments": { | ||
"patch": [ | ||
{ | ||
"comment": "Added support for local API definition resolution\"" | ||
} | ||
] | ||
} | ||
}, | ||
{ | ||
"version": "1.1.11", | ||
@@ -7,0 +19,0 @@ "tag": "@microsoft/api-extractor_v1.1.11", |
# Change Log - @microsoft/api-extractor | ||
This log was last generated on Sat, 11 Feb 2017 02:32:35 GMT and should not be manually modified. | ||
This log was last generated on Thu, 16 Feb 2017 18:56:57 GMT and should not be manually modified. | ||
## 1.1.12 | ||
Thu, 16 Feb 2017 18:56:57 GMT | ||
### Patches | ||
- Added support for local API definition resolution" | ||
## 1.1.11 | ||
@@ -6,0 +13,0 @@ Sat, 11 Feb 2017 02:32:35 GMT |
@@ -9,2 +9,3 @@ // NOTE: THIS SOURCE FILE IS FOR DEBUGGING PURPOSES ONLY. | ||
var ApiJsonGenerator_1 = require("./generators/ApiJsonGenerator"); | ||
var ApiDefinitionReference_1 = require("./ApiDefinitionReference"); | ||
var compilerOptions = { | ||
@@ -35,3 +36,4 @@ target: ts.ScriptTarget.ES5, | ||
}; | ||
console.log(extractor.docItemLoader.getPackage(externalPackageApiRef, console.log)); | ||
var apiDefinitionRef = ApiDefinitionReference_1.default.createFromParts(externalPackageApiRef); | ||
console.log(extractor.docItemLoader.getPackage(apiDefinitionRef, console.log)); | ||
var apiFileGenerator = new ApiFileGenerator_1.default(); | ||
@@ -38,0 +40,0 @@ apiFileGenerator.writeApiFile('./lib/DebugRun.api.ts', extractor); |
/// <reference types="es6-collections" /> | ||
import ApiPackage from './ApiPackage'; | ||
import { IDocElement, IParam } from '../IDocElement'; | ||
import { IDocItem } from '../IDocItem'; | ||
import { IApiDefinitionReference } from '../IApiDefinitionReference'; | ||
import ApiDefinitionReference from '../ApiDefinitionReference'; | ||
import Token from '../Token'; | ||
import Tokenizer from '../Tokenizer'; | ||
import Extractor from '../Extractor'; | ||
import ResolvedApiItem from '../ResolvedApiItem'; | ||
/** | ||
@@ -42,15 +43,2 @@ * An "API Tag" is a custom JSDoc tag which indicates whether an ApiItem definition | ||
/** | ||
* A scope and package name are semantic information within an API reference expression. | ||
*/ | ||
export interface IScopePackageName { | ||
/** | ||
* The scope name of an API reference expression. | ||
*/ | ||
scope: string; | ||
/** | ||
* The package name of an API reference expression. | ||
*/ | ||
package: string; | ||
} | ||
/** | ||
* A dependency for ApiDocumentation constructor that abstracts away the function | ||
@@ -67,3 +55,3 @@ * of resolving an API definition reference. | ||
export interface IReferenceResolver { | ||
resolve(apiDefinitionRef: IApiDefinitionReference, reportError: (message: string) => void): IDocItem; | ||
resolve(apiDefinitionRef: ApiDefinitionReference, apiPackage: ApiPackage, reportError: (message: string) => void): ResolvedApiItem; | ||
} | ||
@@ -79,15 +67,2 @@ export default class ApiDocumentation { | ||
/** | ||
* Splits an API reference expression into two parts, first part is the scopename/packageName and | ||
* the second part is the exportName.memberName. | ||
*/ | ||
private static _packageRegEx; | ||
/** | ||
* Splits the exportName.memberName into two respective parts. | ||
*/ | ||
private static _memberRegEx; | ||
/** | ||
* Used to ensure that the export name contains only text characters. | ||
*/ | ||
private static _exportRegEx; | ||
/** | ||
* The original JsDoc comment. | ||
@@ -159,13 +134,2 @@ * | ||
reportError: (message: string) => void; | ||
/** | ||
* Takes an API reference expression of the form '@scopeName/packageName:exportName.memberName' | ||
* and deconstructs it into an IApiDefinitionReference interface object. | ||
*/ | ||
static parseApiReferenceExpression(apiReferenceExpr: string, reportError: (message: string) => void): IApiDefinitionReference; | ||
/** | ||
* For a scoped NPM package name this separates the scope and package parts. For example: | ||
* parseScopedPackageName('@my-scope/myproject') = { scope: '@my-scope', package: 'myproject' } | ||
* parseScopedPackageName('myproject') = { scope: '', package: 'myproject' } | ||
*/ | ||
private static parseScopedPackageName(scopedName); | ||
constructor(docComment: string, referenceResolver: IReferenceResolver, extractor: Extractor, errorLogger: (message: string) => void); | ||
@@ -172,0 +136,0 @@ protected _parseDocs(): void; |
/* tslint:disable:no-bitwise */ | ||
"use strict"; | ||
var ApiItem_1 = require("./ApiItem"); | ||
var DocElementParser_1 = require("../DocElementParser"); | ||
var ApiDefinitionReference_1 = require("../ApiDefinitionReference"); | ||
var Token_1 = require("../Token"); | ||
@@ -49,56 +51,2 @@ var Tokenizer_1 = require("../Tokenizer"); | ||
} | ||
/** | ||
* Takes an API reference expression of the form '@scopeName/packageName:exportName.memberName' | ||
* and deconstructs it into an IApiDefinitionReference interface object. | ||
*/ | ||
ApiDocumentation.parseApiReferenceExpression = function (apiReferenceExpr, reportError) { | ||
if (!apiReferenceExpr || apiReferenceExpr.split(' ').length > 1) { | ||
reportError('API reference expression must be of the form: ' + | ||
'\'scopeName/packageName:exportName.memberName | display text\'' + | ||
'where the \'|\' is required if a display text is provided'); | ||
return; | ||
} | ||
var apiDefitionRef = { scopeName: '', packageName: '', exportName: '', memberName: '' }; | ||
var parts; | ||
// E.g. @microsoft/sp-core-library:Guid.equals | ||
parts = apiReferenceExpr.match(ApiDocumentation._packageRegEx); | ||
if (parts) { | ||
// parts[1] is of the form ‘@microsoft/sp-core-library’ or ‘sp-core-library’ | ||
var scopePackageName = ApiDocumentation.parseScopedPackageName(parts[1]); | ||
apiDefitionRef.scopeName = scopePackageName.scope; | ||
apiDefitionRef.packageName = scopePackageName.package; | ||
apiReferenceExpr = parts[2]; // e.g. Guid.equals | ||
} | ||
// E.g. Guid.equals | ||
parts = apiReferenceExpr.match(ApiDocumentation._memberRegEx); | ||
if (parts) { | ||
apiDefitionRef.exportName = parts[1]; // e.g. Guid, can never be undefined | ||
apiDefitionRef.memberName = parts[2] ? parts[2] : ''; // e.g. equals | ||
} | ||
else { | ||
// the export name is required | ||
throw reportError("Api reference expression contains invalid characters: " + apiReferenceExpr); | ||
} | ||
if (!apiReferenceExpr.match(ApiDocumentation._exportRegEx)) { | ||
throw reportError("Api reference expression contains invalid characters: " + apiReferenceExpr); | ||
} | ||
return apiDefitionRef; | ||
}; | ||
/** | ||
* For a scoped NPM package name this separates the scope and package parts. For example: | ||
* parseScopedPackageName('@my-scope/myproject') = { scope: '@my-scope', package: 'myproject' } | ||
* parseScopedPackageName('myproject') = { scope: '', package: 'myproject' } | ||
*/ | ||
ApiDocumentation.parseScopedPackageName = function (scopedName) { | ||
if (scopedName.substr(0, 1) !== '@') { | ||
return { scope: '', package: scopedName }; | ||
} | ||
var slashIndex = scopedName.indexOf('/'); | ||
if (slashIndex >= 0) { | ||
return { scope: scopedName.substr(0, slashIndex), package: scopedName.substr(slashIndex + 1) }; | ||
} | ||
else { | ||
throw new Error('Invalid scoped name: ' + scopedName); | ||
} | ||
}; | ||
ApiDocumentation.prototype._parseDocs = function () { | ||
@@ -259,12 +207,13 @@ var tokenizer = new Tokenizer_1.default(this.originalJsDoc, this.reportError); | ||
// Deconstruct the API reference expression 'scopeName/packageName:exportName.memberName' | ||
var apiDefinitionRef = ApiDocumentation.parseApiReferenceExpression(token.text, this.reportError); | ||
var apiDefinitionRef = ApiDefinitionReference_1.default.createFromString(token.text, this.reportError); | ||
// if API reference expression is formatted incorrectly then apiDefinitionRef will be undefined | ||
if (!apiDefinitionRef) { | ||
this.reportError('Incorrecty formatted API definition reference'); | ||
return; | ||
} | ||
// Atempt to locate the apiDefinitionRef | ||
var inheritedDoc = this.referenceResolver.resolve(apiDefinitionRef, this.reportError); | ||
var resolvedApiItem = this.referenceResolver.resolve(apiDefinitionRef, this.extractor.package, this.reportError); | ||
// If no IDocItem found then nothing to inherit | ||
// But for the time being set the summary to a text object | ||
if (!inheritedDoc) { | ||
if (!resolvedApiItem) { | ||
var textDocItem = { | ||
@@ -278,11 +227,15 @@ kind: 'textDocElement', | ||
// inheritdoc found, copy over IDocBase properties | ||
this.summary = inheritedDoc.summary; | ||
this.remarks = inheritedDoc.remarks; | ||
this.summary = resolvedApiItem.summary; | ||
this.remarks = resolvedApiItem.remarks; | ||
// Copy over detailed properties if neccessary | ||
// Add additional cases if needed | ||
switch (inheritedDoc.kind) { | ||
case 'function': | ||
this.parameters = inheritedDoc.parameters; | ||
this.returnsMessage = inheritedDoc.returnValue.description; | ||
switch (resolvedApiItem.kind) { | ||
case ApiItem_1.ApiItemKind.Function: | ||
this.parameters = resolvedApiItem.params; | ||
this.returnsMessage = resolvedApiItem.returnsMessage; | ||
break; | ||
case ApiItem_1.ApiItemKind.Method: | ||
this.parameters = resolvedApiItem.params; | ||
this.returnsMessage = resolvedApiItem.returnsMessage; | ||
break; | ||
} | ||
@@ -292,3 +245,5 @@ // Check if inheritdoc is depreacted | ||
// but it may not appear until after this token. | ||
this.isDocInheritedDeprecated = inheritedDoc.deprecatedMessage.length > 0 ? true : false; | ||
if (resolvedApiItem.deprecatedMessage) { | ||
this.isDocInheritedDeprecated = true; | ||
} | ||
}; | ||
@@ -380,15 +335,2 @@ ApiDocumentation.prototype._parseParam = function (tokenizer) { | ||
]; | ||
/** | ||
* Splits an API reference expression into two parts, first part is the scopename/packageName and | ||
* the second part is the exportName.memberName. | ||
*/ | ||
ApiDocumentation._packageRegEx = /^([^:]*)\:(.*)$/; | ||
/** | ||
* Splits the exportName.memberName into two respective parts. | ||
*/ | ||
ApiDocumentation._memberRegEx = /^([^.|:]*)(?:\.(\w+))?$/; | ||
/** | ||
* Used to ensure that the export name contains only text characters. | ||
*/ | ||
ApiDocumentation._exportRegEx = /^\w+/; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -395,0 +337,0 @@ exports.default = ApiDocumentation; |
@@ -48,2 +48,6 @@ import * as ts from 'typescript'; | ||
TypeLiteral = 9, | ||
/** | ||
* A Typescript class constructor function. | ||
*/ | ||
Constructor = 10, | ||
} | ||
@@ -227,3 +231,3 @@ /** | ||
*/ | ||
resolveReferences(): void; | ||
tryResolveReferences(): boolean; | ||
/** | ||
@@ -230,0 +234,0 @@ * A procedure for determining if this ApiItem is missing type |
@@ -53,2 +53,6 @@ /* tslint:disable:no-bitwise */ | ||
ApiItemKind[ApiItemKind["TypeLiteral"] = 9] = "TypeLiteral"; | ||
/** | ||
* A Typescript class constructor function. | ||
*/ | ||
ApiItemKind[ApiItemKind["Constructor"] = 10] = "Constructor"; | ||
})(ApiItemKind = exports.ApiItemKind || (exports.ApiItemKind = {})); | ||
@@ -216,18 +220,18 @@ /** | ||
*/ | ||
ApiItem.prototype.resolveReferences = function () { | ||
ApiItem.prototype.tryResolveReferences = function () { | ||
switch (this._state) { | ||
case ResolveState.Resolved: | ||
return; | ||
return true; | ||
case ResolveState.Unresolved: | ||
this._state = ResolveState.Resolving; | ||
this.onResolveReferences(); | ||
this._state = ResolveState.Resolved; | ||
for (var _i = 0, _a = this.innerItems; _i < _a.length; _i++) { | ||
var innerItem = _a[_i]; | ||
innerItem.resolveReferences(); | ||
innerItem.tryResolveReferences(); | ||
} | ||
this.onResolveReferences(); | ||
this._state = ResolveState.Resolved; | ||
return; | ||
return true; | ||
case ResolveState.Resolving: | ||
this.reportError('circular reference'); | ||
return; | ||
return false; | ||
default: | ||
@@ -234,0 +238,0 @@ throw new Error('ApiItem state is invalid'); |
@@ -0,1 +1,2 @@ | ||
/// <reference types="es6-collections" /> | ||
import ApiItem, { IApiItemOptions } from './ApiItem'; | ||
@@ -7,3 +8,3 @@ /** | ||
declare abstract class ApiItemContainer extends ApiItem { | ||
memberItems: ApiItem[]; | ||
memberItems: Map<string, ApiItem>; | ||
constructor(options: IApiItemOptions); | ||
@@ -10,0 +11,0 @@ /** |
@@ -16,3 +16,3 @@ "use strict"; | ||
var _this = _super.call(this, options) || this; | ||
_this.memberItems = []; | ||
_this.memberItems = new Map(); | ||
return _this; | ||
@@ -24,3 +24,7 @@ } | ||
ApiItemContainer.prototype.getSortedMemberItems = function () { | ||
return this.memberItems | ||
var apiItems = []; | ||
this.memberItems.forEach(function (apiItem) { | ||
apiItems.push(apiItem); | ||
}); | ||
return apiItems | ||
.sort(function (a, b) { return a.name.localeCompare(b.name); }); | ||
@@ -37,3 +41,3 @@ }; | ||
this.innerItems.push(apiItem); | ||
this.memberItems.push(apiItem); | ||
this.memberItems.set(apiItem.name, apiItem); | ||
} | ||
@@ -40,0 +44,0 @@ }; |
import * as ts from 'typescript'; | ||
import Extractor from '../Extractor'; | ||
import ApiItem from './ApiItem'; | ||
import ApiItemContainer from './ApiItemContainer'; | ||
@@ -11,3 +12,9 @@ /** | ||
constructor(extractor: Extractor, rootFile: ts.SourceFile); | ||
/** | ||
* Find a member in this package by name and return it if found. | ||
* | ||
* @param memberName - the name of the member ApiItem | ||
*/ | ||
getMemberItem(memberName: string): ApiItem; | ||
shouldHaveDocumentation(): boolean; | ||
} |
@@ -82,2 +82,13 @@ /* tslint:disable:no-bitwise */ | ||
}; | ||
/** | ||
* Find a member in this package by name and return it if found. | ||
* | ||
* @param memberName - the name of the member ApiItem | ||
*/ | ||
ApiPackage.prototype.getMemberItem = function (memberName) { | ||
if (this.memberItems.has(memberName)) { | ||
return this.memberItems.get(memberName); | ||
} | ||
return undefined; | ||
}; | ||
ApiPackage.prototype.shouldHaveDocumentation = function () { | ||
@@ -84,0 +95,0 @@ // We don't write JSDoc for the ApiPackage object |
@@ -86,5 +86,4 @@ /* tslint:disable:no-bitwise */ | ||
// Throw errors for setters that don't have a corresponding getter | ||
var memberNames = _this.memberItems.map(function (apiItem) { return apiItem.name; }); | ||
_this._setterNames.forEach(function (setterName) { | ||
if (memberNames.indexOf(setterName) < 0) { | ||
if (!_this.memberItems.has(setterName)) { | ||
_this.reportError("Found setter named " + setterName + " with no corresponding getter. WriteOnly properties are prohibited."); | ||
@@ -91,0 +90,0 @@ } |
@@ -36,49 +36,2 @@ /// <reference types="mocha" /> | ||
var apiDoc = new ApiDocumentation_1.default('Some summary\n@remarks and some remarks\n@public', extractor.docItemLoader, extractor, console.log); | ||
var apiReferenceExpr; | ||
var expected; | ||
var actual; | ||
it('_parseApiReferenceExpression() with scope name', function () { | ||
apiReferenceExpr = '@microsoft/sp-core-library:Guid'; | ||
expected = { | ||
scopeName: '@microsoft', | ||
packageName: 'sp-core-library', | ||
exportName: 'Guid', | ||
memberName: '' | ||
}; | ||
actual = ApiDocumentation_1.default.parseApiReferenceExpression(apiReferenceExpr, apiDoc.reportError); | ||
chai_1.assert.equal(expected.scopeName, actual.scopeName); | ||
chai_1.assert.equal(expected.packageName, actual.packageName); | ||
chai_1.assert.equal(expected.exportName, actual.exportName); | ||
chai_1.assert.equal(expected.memberName, actual.memberName); | ||
}); | ||
it('_parseApiReferenceExpression() without scope name', function () { | ||
apiReferenceExpr = 'sp-core-library:Guid'; | ||
expected = { scopeName: '', packageName: 'sp-core-library', exportName: 'Guid', memberName: '' }; | ||
actual = ApiDocumentation_1.default.parseApiReferenceExpression(apiReferenceExpr, apiDoc.reportError); | ||
chai_1.assert.equal(expected.scopeName, actual.scopeName); | ||
chai_1.assert.equal(expected.packageName, actual.packageName); | ||
chai_1.assert.equal(expected.exportName, actual.exportName); | ||
chai_1.assert.equal(expected.memberName, actual.memberName); | ||
}); | ||
it('_parseApiReferenceExpression() without scope name and with member name', function () { | ||
apiReferenceExpr = 'sp-core-library:Guid.equals'; | ||
expected = { scopeName: '', packageName: 'sp-core-library', exportName: 'Guid', memberName: 'equals' }; | ||
actual = ApiDocumentation_1.default.parseApiReferenceExpression(apiReferenceExpr, apiDoc.reportError); | ||
chai_1.assert.equal(expected.scopeName, actual.scopeName); | ||
chai_1.assert.equal(expected.packageName, actual.packageName); | ||
chai_1.assert.equal(expected.exportName, actual.exportName); | ||
chai_1.assert.equal(expected.memberName, actual.memberName); | ||
}); | ||
it('_parseApiReferenceExpression() without scope name and invalid memberName', function () { | ||
// (Error #6) | ||
apiReferenceExpr = 'sp-core-library:Guid:equals'; | ||
var caughtError = false; | ||
try { | ||
actual = ApiDocumentation_1.default.parseApiReferenceExpression(apiReferenceExpr, apiDoc.reportError); | ||
} | ||
catch (error) { | ||
caughtError = true; | ||
} | ||
chai_1.assert.equal(caughtError, true); | ||
}); | ||
}); | ||
@@ -85,0 +38,0 @@ describe('Documentation Parser Tests', function () { |
"use strict"; | ||
var ApiDocumentation_1 = require("./definitions/ApiDocumentation"); | ||
var ApiDefinitionReference_1 = require("./ApiDefinitionReference"); | ||
var Token_1 = require("./Token"); | ||
@@ -108,3 +108,3 @@ var DocElementParser = (function () { | ||
if (pipeSplitContent.length > 2) { | ||
reportError('Invalid @link parameters, at most pipe character allowed.'); | ||
reportError('Invalid @link parameters, at most one pipe character allowed.'); | ||
return; | ||
@@ -130,3 +130,3 @@ } | ||
// we are processing an API definition reference | ||
var apiDefitionRef = ApiDocumentation_1.default.parseApiReferenceExpression(pipeSplitContent[0], reportError); | ||
var apiDefitionRef = ApiDefinitionReference_1.default.createFromString(pipeSplitContent[0], reportError); | ||
// Once we can locate local API definitions, an error should be reported here if not found. | ||
@@ -133,0 +133,0 @@ if (apiDefitionRef) { |
@@ -1,3 +0,5 @@ | ||
import { IDocItem, IDocPackage } from './IDocItem'; | ||
import { IApiDefinitionReference } from './IApiDefinitionReference'; | ||
import { IDocPackage } from './IDocItem'; | ||
import ApiDefinitionReference from './ApiDefinitionReference'; | ||
import ApiPackage from './definitions/ApiPackage'; | ||
import ResolvedApiItem from './ResolvedApiItem'; | ||
/** | ||
@@ -27,3 +29,2 @@ * Used to describe a parsed package name in the form of | ||
private _projectFolder; | ||
private _errorHandler; | ||
/** | ||
@@ -35,6 +36,17 @@ * The projectFolder is the top-level folder containing package.json for a project | ||
/** | ||
* {@inheritdoc ApiDocumentation.IReferenceResolver} | ||
* {@inheritdoc IReferenceResolver.resolve} | ||
*/ | ||
resolve(apiDefinitionRef: IApiDefinitionReference, reportError: (message: string) => void): IDocItem; | ||
resolve(apiDefinitionRef: ApiDefinitionReference, apiPackage: ApiPackage, reportError: (message: string) => void): ResolvedApiItem; | ||
/** | ||
* Resolution of API definition references in the scenario that the reference given indicates | ||
* that we should search within the current ApiPackage to resolve. | ||
*/ | ||
resolveLocalReferences(apiDefinitionRef: ApiDefinitionReference, apiPackage: ApiPackage, reportError: (message: string) => void): ResolvedApiItem; | ||
/** | ||
* Resolution of API definition references in the scenario that the reference given indicates | ||
* that we should search outside of this ApiPackage and instead search within the JSON API file | ||
* that is associated with the apiDefinitionRef. | ||
*/ | ||
resolveJsonReferences(apiDefinitionRef: ApiDefinitionReference, reportError: (message: string) => void): ResolvedApiItem; | ||
/** | ||
* Attempts to locate and load the IDocPackage object from the project folder's | ||
@@ -45,3 +57,3 @@ * node modules. If the package already exists in the cache, nothing is done. | ||
*/ | ||
getPackage(apiDefinitionRef: IApiDefinitionReference, reportError: (message: string) => void): IDocPackage; | ||
getPackage(apiDefinitionRef: ApiDefinitionReference, reportError: (message: string) => void): IDocPackage; | ||
/** | ||
@@ -48,0 +60,0 @@ * Loads the API documentation json file and validates that it conforms to our schema. If it does, |
@@ -5,2 +5,4 @@ "use strict"; | ||
var path = require("path"); | ||
var ApiItemContainer_1 = require("./definitions/ApiItemContainer"); | ||
var ResolvedApiItem_1 = require("./ResolvedApiItem"); | ||
var JsonFile_1 = require("./JsonFile"); | ||
@@ -27,34 +29,102 @@ /** | ||
/** | ||
* {@inheritdoc ApiDocumentation.IReferenceResolver} | ||
* {@inheritdoc IReferenceResolver.resolve} | ||
*/ | ||
DocItemLoader.prototype.resolve = function (apiDefinitionRef, reportError) { | ||
if (!apiDefinitionRef) { | ||
reportError('Expected reference within {@inheritdoc} tag'); | ||
DocItemLoader.prototype.resolve = function (apiDefinitionRef, apiPackage, reportError) { | ||
// If there is a packageName then there must be a scopeName, and they | ||
// both must match the current scope and package we are in. | ||
// We can take advantage of '&&' being evaluated left to right. | ||
if (!apiDefinitionRef.packageName && !apiDefinitionRef.scopeName) { | ||
// Resolution for local references | ||
return this.resolveLocalReferences(apiDefinitionRef, apiPackage, reportError); | ||
} | ||
else { | ||
// Resolution for references in JSON files | ||
return this.resolveJsonReferences(apiDefinitionRef, reportError); | ||
} | ||
}; | ||
/** | ||
* Resolution of API definition references in the scenario that the reference given indicates | ||
* that we should search within the current ApiPackage to resolve. | ||
*/ | ||
DocItemLoader.prototype.resolveLocalReferences = function (apiDefinitionRef, apiPackage, reportError) { | ||
var apiItem = apiPackage.getMemberItem(apiDefinitionRef.exportName); | ||
// Check if export name was not found | ||
if (!apiItem) { | ||
reportError("Unable to find referenced export \"" + apiDefinitionRef.toExportString() + "\""); | ||
return undefined; | ||
} | ||
// Try to load the package given the provided packageName into the cache | ||
// If memberName exists then check for the existense of the name | ||
if (apiDefinitionRef.memberName) { | ||
if (apiItem instanceof ApiItemContainer_1.default) { | ||
var apiItemContainer = apiItem; | ||
// get() returns undefined if there is no match | ||
apiItem = apiItemContainer.memberItems.get(apiDefinitionRef.memberName); | ||
} | ||
else { | ||
// There are no other instances of apiItem that has members, | ||
// thus there must be a mistake with the apiDefinitionRef. | ||
apiItem = undefined; | ||
} | ||
} | ||
if (!apiItem) { | ||
// If we are here, we can be sure there was a problem with the memberName. | ||
// memberName was not found, apiDefinitionRef is invalid | ||
reportError("Unable to find referenced member \"" + apiDefinitionRef.toMemberString() + "\""); | ||
return undefined; | ||
} | ||
apiItem.tryResolveReferences(); | ||
return ResolvedApiItem_1.default.createFromApiItem(apiItem); | ||
}; | ||
/** | ||
* Resolution of API definition references in the scenario that the reference given indicates | ||
* that we should search outside of this ApiPackage and instead search within the JSON API file | ||
* that is associated with the apiDefinitionRef. | ||
*/ | ||
DocItemLoader.prototype.resolveJsonReferences = function (apiDefinitionRef, reportError) { | ||
// Check if package can be not found | ||
var docPackage = this.getPackage(apiDefinitionRef, reportError); | ||
// Check if package was not found | ||
if (!docPackage) { | ||
// Error is reported in this.getPackage() | ||
return undefined; | ||
} | ||
if (apiDefinitionRef.exportName in docPackage.exports) { | ||
var docItem = docPackage.exports[apiDefinitionRef.exportName]; | ||
// If memberName exists then check for the existense of the name | ||
if (apiDefinitionRef.memberName) { | ||
if (apiDefinitionRef.memberName in docItem.members) { | ||
docItem = docItem.members[apiDefinitionRef.memberName]; | ||
} | ||
else { | ||
// member name was not found, apiDefinitionRef is invalid | ||
return undefined; | ||
} | ||
// found JSON package, now ensure export name is there | ||
// hasOwnProperty() not needed for JJU objects | ||
if (!(apiDefinitionRef.exportName in docPackage.exports)) { | ||
reportError("Unable to find referenced export \"" + apiDefinitionRef.toExportString() + "\"\""); | ||
return undefined; | ||
} | ||
var docItem = docPackage.exports[apiDefinitionRef.exportName]; | ||
// If memberName exists then check for the existense of the name | ||
if (apiDefinitionRef.memberName) { | ||
var member = undefined; | ||
switch (docItem.kind) { | ||
case 'class': | ||
// hasOwnProperty() not needed for JJU objects | ||
member = apiDefinitionRef.memberName in docItem.members ? | ||
docItem.members[apiDefinitionRef.memberName] : undefined; | ||
break; | ||
case 'interface': | ||
// hasOwnProperty() not needed for JJU objects | ||
member = apiDefinitionRef.memberName in docItem.members ? | ||
docItem.members[apiDefinitionRef.memberName] : undefined; | ||
break; | ||
case 'enum': | ||
// hasOwnProperty() not needed for JJU objects | ||
member = apiDefinitionRef.memberName in docItem.values ? | ||
docItem.values[apiDefinitionRef.memberName] : undefined; | ||
break; | ||
default: | ||
// Any other docItem.kind does not have a 'members' property | ||
break; | ||
} | ||
// Correct doc item was found | ||
return docItem; | ||
if (member) { | ||
docItem = member; | ||
} | ||
else { | ||
// member name was not found, apiDefinitionRef is invalid | ||
reportError('Unable to find referenced member \"${apiDefinitionRef.toMemberString()}\"'); | ||
return undefined; | ||
} | ||
} | ||
else { | ||
// Not found | ||
return undefined; | ||
} | ||
return ResolvedApiItem_1.default.createFromJson(docItem); | ||
}; | ||
@@ -80,6 +150,2 @@ /** | ||
} | ||
if (!apiDefinitionRef.packageName) { | ||
// Local export resolution is currently not supported yet | ||
return; | ||
} | ||
// Doesn't exist in cache, attempt to load the json file | ||
@@ -89,3 +155,3 @@ var packageJsonFilePath = path.join(this._projectFolder, 'node_modules', apiDefinitionRef.scopeName, apiDefinitionRef.packageName, "dist/" + apiDefinitionRef.packageName + ".api.json"); | ||
// package not found in node_modules | ||
reportError("@inheritdoc referenced package (\"" + apiDefinitionRef.packageName + "\") not found in node modules."); | ||
reportError("Unable to find referenced package \"" + apiDefinitionRef.toScopePackageString() + "\""); | ||
return; | ||
@@ -92,0 +158,0 @@ } |
@@ -43,3 +43,3 @@ "use strict"; | ||
this.package = new ApiPackage_1.default(this, rootFile); // construct members | ||
this.package.resolveReferences(); // creates ApiDocumentation | ||
this.package.tryResolveReferences(); // creates ApiDocumentation | ||
}; | ||
@@ -46,0 +46,0 @@ /** |
@@ -24,10 +24,2 @@ import Extractor from '../Extractor'; | ||
private static _methodCounter; | ||
private static _KIND_CONSTRUCTOR; | ||
private static _KIND_CLASS; | ||
private static _KIND_ENUM; | ||
private static _KIND_INTERFACE; | ||
private static _KIND_FUNCTION; | ||
private static _KIND_PACKAGE; | ||
private static _KIND_PROPERTY; | ||
private static _KIND_METHOD; | ||
private static _MEMBERS_KEY; | ||
@@ -34,0 +26,0 @@ private static _EXPORTS_KEY; |
@@ -15,2 +15,3 @@ "use strict"; | ||
var JsonFile_1 = require("../JsonFile"); | ||
var ApiJsonFile_1 = require("./ApiJsonFile"); | ||
/** | ||
@@ -53,5 +54,5 @@ * For a library such as "example-package", ApiFileGenerator generates the "example-package.api.ts" | ||
ApiJsonGenerator.prototype.visitApiStructuredType = function (apiStructuredType, refObject) { | ||
var kind = apiStructuredType.kind === ApiItem_1.ApiItemKind.Class ? ApiJsonGenerator._KIND_CLASS : | ||
apiStructuredType.kind === ApiItem_1.ApiItemKind.Interface ? ApiJsonGenerator._KIND_INTERFACE : | ||
''; | ||
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 = { | ||
@@ -82,3 +83,3 @@ kind: kind, | ||
var enumNode = { | ||
kind: ApiJsonGenerator._KIND_ENUM, | ||
kind: ApiJsonFile_1.default.convertKindToJson(apiEnum.kind), | ||
values: valuesNode, | ||
@@ -102,2 +103,3 @@ deprecatedMessage: apiEnum.documentation.deprecatedMessage || [], | ||
refObject[apiEnumValue.name] = { | ||
kind: ApiJsonFile_1.default.convertKindToJson(apiEnumValue.kind), | ||
value: value, | ||
@@ -120,3 +122,3 @@ deprecatedMessage: apiEnumValue.documentation.deprecatedMessage || [], | ||
var newNode = { | ||
kind: ApiJsonGenerator._KIND_FUNCTION, | ||
kind: ApiJsonFile_1.default.convertKindToJson(apiFunction.kind), | ||
returnValue: returnValueNode, | ||
@@ -132,5 +134,7 @@ parameters: apiFunction.documentation.parameters, | ||
ApiJsonGenerator.prototype.visitApiPackage = function (apiPackage, refObject) { | ||
refObject['kind'] = ApiJsonGenerator._KIND_PACKAGE; /* tslint:disable-line:no-string-literal */ | ||
refObject['summary'] = apiPackage.documentation.summary; /* tslint:disable-line:no-string-literal */ | ||
refObject['remarks'] = apiPackage.documentation.remarks; /* tslint:disable-line:no-string-literal */ | ||
/* 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 = {}; | ||
@@ -151,3 +155,3 @@ refObject[ApiJsonGenerator._EXPORTS_KEY] = membersNode; | ||
var newNode = { | ||
kind: ApiJsonGenerator._KIND_PROPERTY, | ||
kind: ApiJsonFile_1.default.convertKindToJson(apiProperty.kind), | ||
isOptional: !!apiProperty.isOptional, | ||
@@ -172,3 +176,3 @@ isReadOnly: !!apiProperty.isReadOnly, | ||
newNode = { | ||
kind: ApiJsonGenerator._KIND_CONSTRUCTOR, | ||
kind: ApiJsonFile_1.default.convertKindToJson(ApiItem_1.ApiItemKind.Constructor), | ||
signature: apiMethod.getDeclarationLine(), | ||
@@ -187,3 +191,3 @@ parameters: apiMethod.documentation.parameters, | ||
newNode = { | ||
kind: ApiJsonGenerator._KIND_METHOD, | ||
kind: ApiJsonFile_1.default.convertKindToJson(apiMethod.kind), | ||
signature: apiMethod.getDeclarationLine(), | ||
@@ -213,10 +217,2 @@ accessModifier: apiMethod.accessModifier ? ApiMember_1.AccessModifier[apiMethod.accessModifier].toLowerCase() : '', | ||
ApiJsonGenerator._methodCounter = 0; | ||
ApiJsonGenerator._KIND_CONSTRUCTOR = 'constructor'; | ||
ApiJsonGenerator._KIND_CLASS = 'class'; | ||
ApiJsonGenerator._KIND_ENUM = 'enum'; | ||
ApiJsonGenerator._KIND_INTERFACE = 'interface'; | ||
ApiJsonGenerator._KIND_FUNCTION = 'function'; | ||
ApiJsonGenerator._KIND_PACKAGE = 'package'; | ||
ApiJsonGenerator._KIND_PROPERTY = 'property'; | ||
ApiJsonGenerator._KIND_METHOD = 'method'; | ||
ApiJsonGenerator._MEMBERS_KEY = 'members'; | ||
@@ -223,0 +219,0 @@ ApiJsonGenerator._EXPORTS_KEY = 'exports'; |
@@ -73,3 +73,3 @@ import { IDocElement } from './IDocElement'; | ||
/** | ||
* kind of DocItem. Ex: 'class', 'Enum', 'Function' | ||
* kind of DocItem. Ex: 'class', 'Enum', 'Function', etc. | ||
*/ | ||
@@ -87,2 +87,6 @@ kind: string; | ||
/** | ||
* {@inheritdoc IDocBase.kind} | ||
*/ | ||
kind: 'property'; | ||
/** | ||
* For an interface member, whether it is optional | ||
@@ -109,2 +113,6 @@ */ | ||
/** | ||
* {@inheritdoc IDocBase.kind} | ||
*/ | ||
kind: 'method'; | ||
/** | ||
* a text summary of the method definition | ||
@@ -141,2 +149,6 @@ */ | ||
/** | ||
* {@inheritdoc IDocBase.kind} | ||
*/ | ||
kind: 'function'; | ||
/** | ||
* parameters of the function | ||
@@ -158,2 +170,6 @@ */ | ||
/** | ||
* {@inheritdoc IDocBase.kind} | ||
*/ | ||
kind: 'class'; | ||
/** | ||
* Can be a combination of methods and/or properties | ||
@@ -181,2 +197,6 @@ */ | ||
export interface IDocEnum extends IDocBase { | ||
/** | ||
* {@inheritdoc IDocBase.kind} | ||
*/ | ||
kind: 'enum'; | ||
values: IDocEnumValue[]; | ||
@@ -189,2 +209,6 @@ } | ||
/** | ||
* {@inheritdoc IDocBase.kind} | ||
*/ | ||
kind: 'interface'; | ||
/** | ||
* A mapping from the name of a member API to its IDocMember | ||
@@ -215,5 +239,5 @@ */ | ||
/** | ||
* Always should be 'package' | ||
*/ | ||
kind: string; | ||
* {@inheritdoc IDocBase.kind} | ||
*/ | ||
kind: 'package'; | ||
/** | ||
@@ -220,0 +244,0 @@ * IDocItems of exported API items |
/// <reference types="mocha" /> | ||
"use strict"; | ||
var DocItemLoader_1 = require("../DocItemLoader"); | ||
var chai_1 = require("chai"); | ||
var ts = require("typescript"); | ||
var path = require("path"); | ||
var Extractor_1 = require("../Extractor"); | ||
var TestFileComparer_1 = require("../TestFileComparer"); | ||
var JsonFile_1 = require("../JsonFile"); | ||
var ApiJsonGenerator_1 = require("../generators/ApiJsonGenerator"); | ||
/* tslint:disable:no-function-expression - Mocha uses a poorly scoped "this" pointer */ | ||
var capturedErrors = []; | ||
function testErrorHandler(message, fileName, lineNumber) { | ||
capturedErrors.push({ message: message, fileName: fileName, lineNumber: lineNumber }); | ||
} | ||
describe('DocItemLoader tests', function () { | ||
this.timeout(10000); | ||
describe('Basic Tests', function () { | ||
it('Should locate external scoped package api item', function () { | ||
var apiDefRef = { | ||
scopeName: '@microsoft', | ||
packageName: 'sp-core-library', | ||
exportName: 'DisplayMode', | ||
memberName: '' | ||
it('Example 3', function () { | ||
var inputFolder = './testInputs/example3'; | ||
var outputFile = './lib/example3-output.json'; | ||
var expectedFile = path.join(inputFolder, 'example3-output.json'); | ||
var compilerOptions = { | ||
target: ts.ScriptTarget.ES5, | ||
module: ts.ModuleKind.CommonJS, | ||
moduleResolution: ts.ModuleResolutionKind.NodeJs, | ||
rootDir: inputFolder, | ||
typeRoots: ['./'] // We need to ignore @types in these tests | ||
}; | ||
var docItemLoader = new DocItemLoader_1.default('./testInputs/example2'); | ||
/* ts-lint:diasble:no-unused-variable */ | ||
var apiDocItem = docItemLoader.resolve(apiDefRef, console.log); | ||
JsonFile_1.default.saveJsonFile('./lib/inheritedDoc-output.json', JSON.stringify(apiDocItem)); | ||
TestFileComparer_1.default.assertFileMatchesExpected('./lib/inheritedDoc-output.json', './testInputs/inheritedDoc-output.json'); | ||
var extractor = new Extractor_1.default({ | ||
compilerOptions: compilerOptions, | ||
errorHandler: testErrorHandler | ||
}); | ||
extractor.loadExternalPackages('./testInputs/external-api-json'); | ||
extractor.analyze({ | ||
entryPointFile: path.join(inputFolder, 'index.ts') | ||
}); | ||
var apiJsonGenerator = new ApiJsonGenerator_1.default(); | ||
apiJsonGenerator.writeJsonFile(outputFile, extractor); | ||
chai_1.assert.equal(capturedErrors.length, 3); | ||
chai_1.assert.equal(capturedErrors[0].message, 'Unable to find referenced member \"MyClass.methodWithTwoParams\"'); | ||
chai_1.assert.equal(capturedErrors[1].message, 'circular reference'); | ||
chai_1.assert.equal(capturedErrors[2].message, 'circular reference'); | ||
TestFileComparer_1.default.assertFileMatchesExpected(outputFile, expectedFile); | ||
}); | ||
@@ -23,0 +44,0 @@ }); |
{ | ||
"name": "@microsoft/api-extractor", | ||
"version": "1.1.11", | ||
"version": "1.1.12", | ||
"description": "Validatation, documentation, and auditing for the exported API of a TypeScript package", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
606895
153
7489