Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add UidGenerator for stable UID generation across projects #1

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions apps/api-extractor-model/src/items/ApiItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ export const enum ApiItemKind {
* @public
*/
export interface IApiItemOptions {
uid?: string;
}

export interface IApiItemJson {
kind: ApiItemKind;
canonicalReference: string;
uid?: string;
}

/**
Expand All @@ -65,6 +67,8 @@ export const ApiItem_parent: unique symbol = Symbol('ApiItem._parent');
export class ApiItem {
public [ApiItem_parent]: ApiItem | undefined;

private _uid: string | undefined;

public static deserialize(jsonObject: IApiItemJson, context: DeserializerContext): ApiItem {
// The Deserializer class is coupled with a ton of other classes, so we delay loading it
// to avoid ES5 circular imports.
Expand All @@ -73,19 +77,24 @@ export class ApiItem {
}

/** @virtual */
public static onDeserializeInto(options: Partial<IApiItemOptions>, context: DeserializerContext,
public static onDeserializeInto(options: Partial<IApiItemOptions>, context: DeserializerContext,
jsonObject: IApiItemJson): void {
// (implemented by subclasses)
if (jsonObject.uid !== undefined) {
options.uid = jsonObject.uid;
}
}

public constructor(options: IApiItemOptions) {
// ("options" is not used here, but part of the inheritance pattern)
this._uid = options.uid;
}

/** @virtual */
public serializeInto(jsonObject: Partial<IApiItemJson>): void {
jsonObject.kind = this.kind;
jsonObject.canonicalReference = this.canonicalReference;
if (this._uid !== undefined) {
jsonObject.uid = this._uid;
}
}

/** @virtual */
Expand All @@ -98,6 +107,10 @@ export class ApiItem {
throw new Error('ApiItem.canonicalReference was not implemented by the child class');
}

public get uid(): string {
return this._uid || '';
}

/**
* Returns a name for this object that can be used in diagnostic messages, for example.
*
Expand Down
33 changes: 33 additions & 0 deletions apps/api-extractor/src/analyzer/TypeScriptInternals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@

import * as ts from 'typescript';

export interface IMappedType extends ts.ObjectType {
declaration: ts.MappedTypeNode;
typeParameter?: ts.TypeParameter;
constraintType?: ts.Type;
templateType?: ts.Type;
modifiersType?: ts.Type;
resolvedApparentType?: ts.Type;
}

export class TypeScriptInternals {

public static getImmediateAliasedSymbol(symbol: ts.Symbol, typeChecker: ts.TypeChecker): ts.Symbol {
Expand Down Expand Up @@ -83,4 +92,28 @@ export class TypeScriptInternals {
public static getSymbolParent(symbol: ts.Symbol): ts.Symbol | undefined {
return (symbol as any).parent;
}

/**
* Determines whether a type is the 'this' type parameter.
*/
public static isThisType(type: ts.Type): boolean {
// tslint:disable-next-line:no-bitwise
return type.flags & ts.TypeFlags.TypeParameter
? (type as any).isThisType || false
: false;
}

public static getMappedType(type: ts.Type): IMappedType | undefined {
if (isMappedType(type)) {
return <IMappedType>type;
}
return undefined;
}
}

function isMappedType(type: ts.Type): boolean {
// tslint:disable-next-line:no-bitwise
return !!(type.flags & ts.TypeFlags.Object)
// tslint:disable-next-line:no-bitwise
&& !!((type as ts.ObjectType).objectFlags & ts.ObjectFlags.Mapped);
}
56 changes: 39 additions & 17 deletions apps/api-extractor/src/generators/ApiModelGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,23 @@ import { Collector } from '../collector/Collector';
import { AstDeclaration } from '../analyzer/AstDeclaration';
import { ExcerptBuilder, IExcerptBuilderNodeToCapture } from './ExcerptBuilder';
import { AstSymbol } from '../analyzer/AstSymbol';
import { UidGenerator } from './UidGenerator';

export class ApiModelGenerator {
private readonly _collector: Collector;
private readonly _cachedOverloadIndexesByDeclaration: Map<AstDeclaration, number>;
private readonly _apiModel: ApiModel;
private readonly _uidGenerator: UidGenerator;

public constructor(collector: Collector) {
this._collector = collector;
this._cachedOverloadIndexesByDeclaration = new Map<AstDeclaration, number>();
this._apiModel = new ApiModel();
this._uidGenerator = new UidGenerator(
collector.packageJsonLookup,
collector.program,
collector.typeChecker,
collector.workingPackage.name);
}

public get apiModel(): ApiModel {
Expand All @@ -56,9 +63,11 @@ export class ApiModelGenerator {
public buildApiPackage(): ApiPackage {
const packageDocComment: tsdoc.DocComment | undefined = this._collector.workingPackage.tsdocComment;

const name: string = this._collector.workingPackage.name;
const apiPackage: ApiPackage = new ApiPackage({
name: this._collector.workingPackage.name,
docComment: packageDocComment
name,
docComment: packageDocComment,
uid: `${name}/`
});
this._apiModel.addMember(apiPackage);

Expand Down Expand Up @@ -213,6 +222,7 @@ export class ApiModelGenerator {

const overloadIndex: number = this._getOverloadIndex(astDeclaration);
const canonicalReference: string = ApiConstructor.getCanonicalReference(overloadIndex);
const uid: string = this._uidGenerator.getUidOfDeclaration(astDeclaration.declaration);

let apiConstructor: ApiConstructor | undefined = parentApiItem.tryGetMember(canonicalReference) as ApiConstructor;

Expand All @@ -232,7 +242,7 @@ export class ApiModelGenerator {
const docComment: tsdoc.DocComment | undefined = this._collector.fetchMetadata(astDeclaration).tsdocComment;
const releaseTag: ReleaseTag = this._collector.fetchMetadata(astDeclaration.astSymbol).releaseTag;

apiConstructor = new ApiConstructor({ docComment, releaseTag, parameters, overloadIndex,
apiConstructor = new ApiConstructor({ uid, docComment, releaseTag, parameters, overloadIndex,
excerptTokens });

parentApiItem.addMember(apiConstructor);
Expand All @@ -244,6 +254,7 @@ export class ApiModelGenerator {

const name: string = !!exportedName ? exportedName : astDeclaration.astSymbol.localName;
const canonicalReference: string = ApiClass.getCanonicalReference(name);
const uid: string = this._uidGenerator.getUidOfDeclaration(astDeclaration.declaration);

let apiClass: ApiClass | undefined = parentApiItem.tryGetMember(canonicalReference) as ApiClass;

Expand Down Expand Up @@ -281,7 +292,7 @@ export class ApiModelGenerator {
const docComment: tsdoc.DocComment | undefined = this._collector.fetchMetadata(astDeclaration).tsdocComment;
const releaseTag: ReleaseTag = this._collector.fetchMetadata(astDeclaration.astSymbol).releaseTag;

apiClass = new ApiClass({ name, docComment, releaseTag, excerptTokens, typeParameters, extendsTokenRange,
apiClass = new ApiClass({ name, uid, docComment, releaseTag, excerptTokens, typeParameters, extendsTokenRange,
implementsTokenRanges });

parentApiItem.addMember(apiClass);
Expand Down Expand Up @@ -332,6 +343,7 @@ export class ApiModelGenerator {

const name: string = !!exportedName ? exportedName : astDeclaration.astSymbol.localName;
const canonicalReference: string = ApiEnum.getCanonicalReference(name);
const uid: string = this._uidGenerator.getUidOfDeclaration(astDeclaration.declaration);

let apiEnum: ApiEnum | undefined = parentApiItem.tryGetMember(canonicalReference) as ApiEnum;

Expand All @@ -344,7 +356,7 @@ export class ApiModelGenerator {
const docComment: tsdoc.DocComment | undefined = this._collector.fetchMetadata(astDeclaration).tsdocComment;
const releaseTag: ReleaseTag = this._collector.fetchMetadata(astDeclaration.astSymbol).releaseTag;

apiEnum = new ApiEnum({ name, docComment, releaseTag, excerptTokens });
apiEnum = new ApiEnum({ name, uid, docComment, releaseTag, excerptTokens });
parentApiItem.addMember(apiEnum);
}

Expand All @@ -356,6 +368,7 @@ export class ApiModelGenerator {

const name: string = !!exportedName ? exportedName : astDeclaration.astSymbol.localName;
const canonicalReference: string = ApiEnumMember.getCanonicalReference(name);
const uid: string = this._uidGenerator.getUidOfDeclaration(astDeclaration.declaration);

let apiEnumMember: ApiEnumMember | undefined = parentApiItem.tryGetMember(canonicalReference) as ApiEnumMember;

Expand All @@ -375,7 +388,7 @@ export class ApiModelGenerator {
const docComment: tsdoc.DocComment | undefined = this._collector.fetchMetadata(astDeclaration).tsdocComment;
const releaseTag: ReleaseTag = this._collector.fetchMetadata(astDeclaration.astSymbol).releaseTag;

apiEnumMember = new ApiEnumMember({ name, docComment, releaseTag,
apiEnumMember = new ApiEnumMember({ name, uid, docComment, releaseTag,
excerptTokens, initializerTokenRange });

parentApiItem.addMember(apiEnumMember);
Expand All @@ -386,9 +399,9 @@ export class ApiModelGenerator {
parentApiItem: ApiItemContainerMixin): void {

const name: string = !!exportedName ? exportedName : astDeclaration.astSymbol.localName;

const overloadIndex: number = this._getOverloadIndex(astDeclaration);
const canonicalReference: string = ApiFunction.getCanonicalReference(name, overloadIndex);
const uid: string = this._uidGenerator.getUidOfDeclaration(astDeclaration.declaration);

let apiFunction: ApiFunction | undefined = parentApiItem.tryGetMember(canonicalReference) as
ApiFunction;
Expand All @@ -414,7 +427,7 @@ export class ApiModelGenerator {
const docComment: tsdoc.DocComment | undefined = this._collector.fetchMetadata(astDeclaration).tsdocComment;
const releaseTag: ReleaseTag = this._collector.fetchMetadata(astDeclaration.astSymbol).releaseTag;

apiFunction = new ApiFunction({ name, docComment, releaseTag, typeParameters, parameters, overloadIndex,
apiFunction = new ApiFunction({ name, uid, docComment, releaseTag, typeParameters, parameters, overloadIndex,
excerptTokens, returnTypeTokenRange });

parentApiItem.addMember(apiFunction);
Expand Down Expand Up @@ -459,6 +472,7 @@ export class ApiModelGenerator {

const name: string = !!exportedName ? exportedName : astDeclaration.astSymbol.localName;
const canonicalReference: string = ApiInterface.getCanonicalReference(name);
const uid: string = this._uidGenerator.getUidOfDeclaration(astDeclaration.declaration);

let apiInterface: ApiInterface | undefined = parentApiItem.tryGetMember(canonicalReference) as ApiInterface;

Expand Down Expand Up @@ -491,7 +505,7 @@ export class ApiModelGenerator {
const docComment: tsdoc.DocComment | undefined = this._collector.fetchMetadata(astDeclaration).tsdocComment;
const releaseTag: ReleaseTag = this._collector.fetchMetadata(astDeclaration.astSymbol).releaseTag;

apiInterface = new ApiInterface({ name, docComment, releaseTag, excerptTokens, typeParameters,
apiInterface = new ApiInterface({ name, uid, docComment, releaseTag, excerptTokens, typeParameters,
extendsTokenRanges });

parentApiItem.addMember(apiInterface);
Expand All @@ -508,6 +522,7 @@ export class ApiModelGenerator {
const isStatic: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Static) !== 0;
const overloadIndex: number = this._getOverloadIndex(astDeclaration);
const canonicalReference: string = ApiMethod.getCanonicalReference(name, isStatic, overloadIndex);
const uid: string = this._uidGenerator.getUidOfDeclaration(astDeclaration.declaration);

let apiMethod: ApiMethod | undefined = parentApiItem.tryGetMember(canonicalReference) as ApiMethod;

Expand All @@ -532,8 +547,8 @@ export class ApiModelGenerator {
const docComment: tsdoc.DocComment | undefined = this._collector.fetchMetadata(astDeclaration).tsdocComment;
const releaseTag: ReleaseTag = this._collector.fetchMetadata(astDeclaration.astSymbol).releaseTag;

apiMethod = new ApiMethod({ name, docComment, releaseTag, isStatic, typeParameters, parameters, overloadIndex,
excerptTokens, returnTypeTokenRange });
apiMethod = new ApiMethod({ name, uid, docComment, releaseTag, isStatic, typeParameters, parameters,
overloadIndex, excerptTokens, returnTypeTokenRange });

parentApiItem.addMember(apiMethod);
}
Expand All @@ -546,6 +561,7 @@ export class ApiModelGenerator {

const overloadIndex: number = this._getOverloadIndex(astDeclaration);
const canonicalReference: string = ApiMethodSignature.getCanonicalReference(name, overloadIndex);
const uid: string = this._uidGenerator.getUidOfDeclaration(astDeclaration.declaration);

let apiMethodSignature: ApiMethodSignature | undefined = parentApiItem.tryGetMember(canonicalReference) as
ApiMethodSignature;
Expand All @@ -570,7 +586,7 @@ export class ApiModelGenerator {
const docComment: tsdoc.DocComment | undefined = this._collector.fetchMetadata(astDeclaration).tsdocComment;
const releaseTag: ReleaseTag = this._collector.fetchMetadata(astDeclaration.astSymbol).releaseTag;

apiMethodSignature = new ApiMethodSignature({ name, docComment, releaseTag, typeParameters, parameters,
apiMethodSignature = new ApiMethodSignature({ name, uid, docComment, releaseTag, typeParameters, parameters,
overloadIndex, excerptTokens, returnTypeTokenRange });

parentApiItem.addMember(apiMethodSignature);
Expand All @@ -582,6 +598,7 @@ export class ApiModelGenerator {

const name: string = !!exportedName ? exportedName : astDeclaration.astSymbol.localName;
const canonicalReference: string = ApiNamespace.getCanonicalReference(name);
const uid: string = this._uidGenerator.getUidOfDeclaration(astDeclaration.declaration);

let apiNamespace: ApiNamespace | undefined = parentApiItem.tryGetMember(canonicalReference) as ApiNamespace;

Expand All @@ -594,7 +611,7 @@ export class ApiModelGenerator {
const docComment: tsdoc.DocComment | undefined = this._collector.fetchMetadata(astDeclaration).tsdocComment;
const releaseTag: ReleaseTag = this._collector.fetchMetadata(astDeclaration.astSymbol).releaseTag;

apiNamespace = new ApiNamespace({ name, docComment, releaseTag, excerptTokens });
apiNamespace = new ApiNamespace({ name, uid, docComment, releaseTag, excerptTokens });
parentApiItem.addMember(apiNamespace);
}

Expand All @@ -609,6 +626,7 @@ export class ApiModelGenerator {
const isStatic: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Static) !== 0;

const canonicalReference: string = ApiProperty.getCanonicalReference(name, isStatic);
const uid: string = this._uidGenerator.getUidOfDeclaration(astDeclaration.declaration);

let apiProperty: ApiProperty | undefined
= parentApiItem.tryGetMember(canonicalReference) as ApiProperty;
Expand All @@ -628,7 +646,8 @@ export class ApiModelGenerator {
const docComment: tsdoc.DocComment | undefined = this._collector.fetchMetadata(astDeclaration).tsdocComment;
const releaseTag: ReleaseTag = this._collector.fetchMetadata(astDeclaration.astSymbol).releaseTag;

apiProperty = new ApiProperty({ name, docComment, releaseTag, isStatic, excerptTokens, propertyTypeTokenRange });
apiProperty = new ApiProperty({ name, uid, docComment, releaseTag, isStatic, excerptTokens,
propertyTypeTokenRange });
parentApiItem.addMember(apiProperty);
} else {
// If the property was already declared before (via a merged interface declaration),
Expand All @@ -641,6 +660,7 @@ export class ApiModelGenerator {

const name: string = !!exportedName ? exportedName : astDeclaration.astSymbol.localName;
const canonicalReference: string = ApiPropertySignature.getCanonicalReference(name);
const uid: string = this._uidGenerator.getUidOfDeclaration(astDeclaration.declaration);

let apiPropertySignature: ApiPropertySignature | undefined
= parentApiItem.tryGetMember(canonicalReference) as ApiPropertySignature;
Expand All @@ -660,7 +680,7 @@ export class ApiModelGenerator {
const docComment: tsdoc.DocComment | undefined = this._collector.fetchMetadata(astDeclaration).tsdocComment;
const releaseTag: ReleaseTag = this._collector.fetchMetadata(astDeclaration.astSymbol).releaseTag;

apiPropertySignature = new ApiPropertySignature({ name, docComment, releaseTag,
apiPropertySignature = new ApiPropertySignature({ name, uid, docComment, releaseTag,
excerptTokens, propertyTypeTokenRange });
parentApiItem.addMember(apiPropertySignature);
} else {
Expand All @@ -675,6 +695,7 @@ export class ApiModelGenerator {
const name: string = !!exportedName ? exportedName : astDeclaration.astSymbol.localName;

const canonicalReference: string = ApiTypeAlias.getCanonicalReference(name);
const uid: string = this._uidGenerator.getUidOfDeclaration(astDeclaration.declaration);

let apiTypeAlias: ApiTypeAlias | undefined = parentApiItem.tryGetMember(canonicalReference) as
ApiTypeAlias;
Expand All @@ -697,7 +718,7 @@ export class ApiModelGenerator {
const docComment: tsdoc.DocComment | undefined = this._collector.fetchMetadata(astDeclaration).tsdocComment;
const releaseTag: ReleaseTag = this._collector.fetchMetadata(astDeclaration.astSymbol).releaseTag;

apiTypeAlias = new ApiTypeAlias({ name, docComment, typeParameters, releaseTag, excerptTokens,
apiTypeAlias = new ApiTypeAlias({ name, uid, docComment, typeParameters, releaseTag, excerptTokens,
typeTokenRange });

parentApiItem.addMember(apiTypeAlias);
Expand All @@ -710,6 +731,7 @@ export class ApiModelGenerator {
const name: string = !!exportedName ? exportedName : astDeclaration.astSymbol.localName;

const canonicalReference: string = ApiVariable.getCanonicalReference(name);
const uid: string = this._uidGenerator.getUidOfDeclaration(astDeclaration.declaration);

let apiVariable: ApiVariable | undefined = parentApiItem.tryGetMember(canonicalReference) as
ApiVariable;
Expand All @@ -729,7 +751,7 @@ export class ApiModelGenerator {
const docComment: tsdoc.DocComment | undefined = this._collector.fetchMetadata(astDeclaration).tsdocComment;
const releaseTag: ReleaseTag = this._collector.fetchMetadata(astDeclaration.astSymbol).releaseTag;

apiVariable = new ApiVariable({ name, docComment, releaseTag, excerptTokens, variableTypeTokenRange });
apiVariable = new ApiVariable({ name, uid, docComment, releaseTag, excerptTokens, variableTypeTokenRange });

parentApiItem.addMember(apiVariable);
}
Expand Down
Loading