forked from microsoft/rushstack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathApiDefinitionReference.ts
More file actions
210 lines (191 loc) · 6.75 KB
/
ApiDefinitionReference.ts
File metadata and controls
210 lines (191 loc) · 6.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/**
* An API definition reference that is used to locate the documentation of exported
* API items that may or may not belong to an external package.
*
* The format of the API definition reference is:
* scopeName/packageName:exportName.memberName
*
* The following are valid API definition references:
* \@microsoft/sp-core-library:DisplayMode
* \@microsoft/sp-core-library:Guid
* \@microsoft/sp-core-library:Guid.equals
* es6-collections:Map
*/
export interface IApiDefinintionReferenceParts {
/**
* This is an optional property to denote that a package name is scoped under this name.
* For example, a common case is when having the '@microsoft' scope name in the
* API definition reference: '\@microsoft/sp-core-library'.
*/
scopeName: string;
/**
* The name of the package that the exportName belongs to.
*/
packageName: string;
/**
* The name of the export API item.
*/
exportName: string;
/**
* The name of the member API item.
*/
memberName: string;
}
/**
* A scope and package name are semantic information within an API reference expression.
* If there is no scope or package, then the corresponding values will be an empty string.
*
* Example: '@microsoft/Utilities' -> \{ scope: '@microsoft', package: 'Utilities' \}
* Example: 'Utilities' -> \{ scope: '', package: 'Utilities' \}
*/
export interface IScopedPackageName {
/**
* The scope name of an API reference expression.
*/
scope: string;
/**
* The package name of an API reference expression.
*/
package: string;
}
/**
* {@inheritdoc IApiDefinintionReferenceParts}
*/
export default class ApiDefinitionReference {
/**
* 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: RegExp = /^([^:]*)\:(.*)$/;
/**
* Splits the exportName.memberName into two respective parts.
*/
private static _memberRegEx: RegExp = /^([^.|:]*)(?:\.(\w+))?$/;
/**
* Used to ensure that the export name contains only text characters.
*/
private static _exportRegEx: RegExp = /^\w+/;
/**
* {@inheritdoc IApiDefinintionReferenceParts.scopeName}
*/
public scopeName: string;
/**
* {@inheritdoc IApiDefinintionReferenceParts.packageName}
*/
public packageName: string;
/**
* {@inheritdoc IApiDefinintionReferenceParts.exportName}
*/
public exportName: string;
/**
* {@inheritdoc IApiDefinintionReferenceParts.memberName}
*/
public memberName: string;
/**
* Creates an ApiDefinitionReference instance given strings that symbolize the public
* properties of ApiDefinitionReference.
*/
public static createFromParts(parts: IApiDefinintionReferenceParts): ApiDefinitionReference {
return new ApiDefinitionReference(parts);
}
/**
* Takes an API reference expression of the form '@scopeName/packageName:exportName.memberName'
* and deconstructs it into an IApiDefinitionReference interface object.
*/
public static createFromString(apiReferenceExpr: string,
reportError: (message: string) => void): ApiDefinitionReference {
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;
}
const apiDefRefParts: IApiDefinintionReferenceParts = {
scopeName: '',
packageName: '',
exportName: '',
memberName: ''
};
// E.g. @microsoft/sp-core-library:Guid.equals
let parts: string[] = apiReferenceExpr.match(ApiDefinitionReference._packageRegEx);
if (parts) {
// parts[1] is of the form ‘@microsoft/sp-core-library’ or ‘sp-core-library’
const scopePackageName: IScopedPackageName = ApiDefinitionReference.parseScopedPackageName(parts[1]);
apiDefRefParts.scopeName = scopePackageName.scope;
apiDefRefParts.packageName = scopePackageName.package;
apiReferenceExpr = parts[2]; // e.g. Guid.equals
}
// E.g. Guid.equals
parts = apiReferenceExpr.match(ApiDefinitionReference._memberRegEx);
if (parts) {
apiDefRefParts.exportName = parts[1]; // e.g. Guid, can never be undefined
apiDefRefParts.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(ApiDefinitionReference._exportRegEx)) {
throw reportError(`Api reference expression contains invalid characters: ${apiReferenceExpr}`);
}
return ApiDefinitionReference.createFromParts(apiDefRefParts);
}
/**
* 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' }
*/
public static parseScopedPackageName(scopedName: string): IScopedPackageName {
if (scopedName.substr(0, 1) !== '@') {
return { scope: '', package: scopedName };
}
const slashIndex: number = scopedName.indexOf('/');
if (slashIndex >= 0) {
return { scope: scopedName.substr(0, slashIndex), package: scopedName.substr(slashIndex + 1) };
} else {
throw new Error('Invalid scoped name: ' + scopedName);
}
}
/**
* Stringifies the ApiDefinitionReferenceOptions up and including the
* scope and package name.
*
* Example output: '@microsoft/Utilities'
*/
public toScopePackageString(): string {
let result: string = '';
if (this.scopeName) {
result += `${this.scopeName}/${this.packageName}`;
} else if (this.packageName) {
result += `$this.packageName`;
}
return result;
}
/**
* Stringifies the ApiDefinitionReferenceOptions up and including the
* scope, package and export name.
*
* Example output: '@microsoft/Utilities.Parse'
*/
public toExportString(): string {
let result: string = this.toScopePackageString();
if (result) {
result += ':';
}
return result + `${this.exportName}`;
}
/**
* Stringifies the ApiDefinitionReferenceOptions up and including the
* scope, package, export and member name.
*
* Example output: '@microsoft/Utilities.Parse.parseJsonToString'
*/
public toMemberString(): string {
return this.toExportString() + `.${this.memberName}`;
}
private constructor(parts: IApiDefinintionReferenceParts) {
this.scopeName = parts.scopeName;
this.packageName = parts.packageName;
this.exportName = parts.exportName;
this.memberName = parts.memberName;
}
}