@microsoft/m365-spec-parser 0.1.1-alpha.149079452.0 → 0.1.1-alpha.18377bc6e.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm2017.js +793 -299
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +943 -409
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +797 -299
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +949 -408
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/constants.d.ts +5 -1
- package/dist/src/index.browser.d.ts +2 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/interfaces.d.ts +86 -18
- package/dist/src/manifestUpdater.d.ts +9 -4
- package/dist/src/specFilter.d.ts +2 -1
- package/dist/src/specParser.browser.d.ts +18 -2
- package/dist/src/specParser.d.ts +18 -3
- package/dist/src/utils.d.ts +18 -34
- package/package.json +4 -4
package/dist/index.esm2017.js
CHANGED
|
@@ -15,7 +15,8 @@ var ErrorType;
|
|
|
15
15
|
ErrorType["NoExtraAPICanBeAdded"] = "no-extra-api-can-be-added";
|
|
16
16
|
ErrorType["ResolveServerUrlFailed"] = "resolve-server-url-failed";
|
|
17
17
|
ErrorType["SwaggerNotSupported"] = "swagger-not-supported";
|
|
18
|
-
ErrorType["
|
|
18
|
+
ErrorType["MultipleAuthNotSupported"] = "multiple-auth-not-supported";
|
|
19
|
+
ErrorType["SpecVersionNotSupported"] = "spec-version-not-supported";
|
|
19
20
|
ErrorType["ListFailed"] = "list-failed";
|
|
20
21
|
ErrorType["listSupportedAPIInfoFailed"] = "list-supported-api-info-failed";
|
|
21
22
|
ErrorType["FilterSpecFailed"] = "filter-spec-failed";
|
|
@@ -23,6 +24,22 @@ var ErrorType;
|
|
|
23
24
|
ErrorType["GenerateAdaptiveCardFailed"] = "generate-adaptive-card-failed";
|
|
24
25
|
ErrorType["GenerateFailed"] = "generate-failed";
|
|
25
26
|
ErrorType["ValidateFailed"] = "validate-failed";
|
|
27
|
+
ErrorType["GetSpecFailed"] = "get-spec-failed";
|
|
28
|
+
ErrorType["AuthTypeIsNotSupported"] = "auth-type-is-not-supported";
|
|
29
|
+
ErrorType["MissingOperationId"] = "missing-operation-id";
|
|
30
|
+
ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
|
|
31
|
+
ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
|
|
32
|
+
ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
|
|
33
|
+
ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
|
|
34
|
+
ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
|
|
35
|
+
ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
|
|
36
|
+
ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
|
|
37
|
+
ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
|
|
38
|
+
ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
|
|
39
|
+
ErrorType["NoParameter"] = "no-parameter";
|
|
40
|
+
ErrorType["NoAPIInfo"] = "no-api-info";
|
|
41
|
+
ErrorType["MethodNotAllowed"] = "method-not-allowed";
|
|
42
|
+
ErrorType["UrlPathNotExist"] = "url-path-not-exist";
|
|
26
43
|
ErrorType["Cancelled"] = "cancelled";
|
|
27
44
|
ErrorType["Unknown"] = "unknown";
|
|
28
45
|
})(ErrorType || (ErrorType = {}));
|
|
@@ -45,7 +62,13 @@ var ValidationStatus;
|
|
|
45
62
|
ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
|
|
46
63
|
ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
|
|
47
64
|
ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
|
|
48
|
-
})(ValidationStatus || (ValidationStatus = {}));
|
|
65
|
+
})(ValidationStatus || (ValidationStatus = {}));
|
|
66
|
+
var ProjectType;
|
|
67
|
+
(function (ProjectType) {
|
|
68
|
+
ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
|
|
69
|
+
ProjectType[ProjectType["SME"] = 1] = "SME";
|
|
70
|
+
ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
|
|
71
|
+
})(ProjectType || (ProjectType = {}));
|
|
49
72
|
|
|
50
73
|
// Copyright (c) Microsoft Corporation.
|
|
51
74
|
class SpecParserError extends Error {
|
|
@@ -72,7 +95,9 @@ ConstantString.ResolveServerUrlFailed = "Unable to resolve the server URL: pleas
|
|
|
72
95
|
ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multiple optional parameters. The first optional parameter is used for this command.";
|
|
73
96
|
ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
|
|
74
97
|
ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
|
|
75
|
-
ConstantString.
|
|
98
|
+
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
99
|
+
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
100
|
+
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
76
101
|
ConstantString.WrappedCardVersion = "devPreview";
|
|
77
102
|
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
78
103
|
ConstantString.WrappedCardResponseLayout = "list";
|
|
@@ -84,6 +109,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
|
84
109
|
ConstantString.TextBlockType = "TextBlock";
|
|
85
110
|
ConstantString.ContainerType = "Container";
|
|
86
111
|
ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
|
|
112
|
+
ConstantString.OAuthRegistrationIdPostFix = "OAUTH_REGISTRATION_ID";
|
|
87
113
|
ConstantString.ResponseCodeFor20X = [
|
|
88
114
|
"200",
|
|
89
115
|
"201",
|
|
@@ -143,205 +169,35 @@ ConstantString.FullDescriptionMaxLens = 4000;
|
|
|
143
169
|
ConstantString.CommandDescriptionMaxLens = 128;
|
|
144
170
|
ConstantString.ParameterDescriptionMaxLens = 128;
|
|
145
171
|
ConstantString.CommandTitleMaxLens = 32;
|
|
146
|
-
ConstantString.ParameterTitleMaxLens = 32;
|
|
172
|
+
ConstantString.ParameterTitleMaxLens = 32;
|
|
173
|
+
ConstantString.SMERequiredParamsMaxNum = 5;
|
|
147
174
|
|
|
148
175
|
// Copyright (c) Microsoft Corporation.
|
|
149
176
|
class Utils {
|
|
150
|
-
static
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
};
|
|
156
|
-
if (!paramObject) {
|
|
157
|
-
return paramResult;
|
|
158
|
-
}
|
|
159
|
-
for (let i = 0; i < paramObject.length; i++) {
|
|
160
|
-
const param = paramObject[i];
|
|
161
|
-
const schema = param.schema;
|
|
162
|
-
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
163
|
-
if (param.in === "header" || param.in === "cookie") {
|
|
164
|
-
if (isRequiredWithoutDefault) {
|
|
165
|
-
paramResult.isValid = false;
|
|
166
|
-
}
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
if (schema.type !== "boolean" &&
|
|
170
|
-
schema.type !== "string" &&
|
|
171
|
-
schema.type !== "number" &&
|
|
172
|
-
schema.type !== "integer") {
|
|
173
|
-
if (isRequiredWithoutDefault) {
|
|
174
|
-
paramResult.isValid = false;
|
|
175
|
-
}
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
if (param.in === "query" || param.in === "path") {
|
|
179
|
-
if (isRequiredWithoutDefault) {
|
|
180
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
return paramResult;
|
|
188
|
-
}
|
|
189
|
-
static checkPostBody(schema, isRequired = false) {
|
|
190
|
-
var _a;
|
|
191
|
-
const paramResult = {
|
|
192
|
-
requiredNum: 0,
|
|
193
|
-
optionalNum: 0,
|
|
194
|
-
isValid: true,
|
|
195
|
-
};
|
|
196
|
-
if (Object.keys(schema).length === 0) {
|
|
197
|
-
return paramResult;
|
|
198
|
-
}
|
|
199
|
-
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
200
|
-
if (schema.type === "string" ||
|
|
201
|
-
schema.type === "integer" ||
|
|
202
|
-
schema.type === "boolean" ||
|
|
203
|
-
schema.type === "number") {
|
|
204
|
-
if (isRequiredWithoutDefault) {
|
|
205
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
206
|
-
}
|
|
207
|
-
else {
|
|
208
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
else if (schema.type === "object") {
|
|
212
|
-
const { properties } = schema;
|
|
213
|
-
for (const property in properties) {
|
|
214
|
-
let isRequired = false;
|
|
215
|
-
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
216
|
-
isRequired = true;
|
|
217
|
-
}
|
|
218
|
-
const result = Utils.checkPostBody(properties[property], isRequired);
|
|
219
|
-
paramResult.requiredNum += result.requiredNum;
|
|
220
|
-
paramResult.optionalNum += result.optionalNum;
|
|
221
|
-
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
else {
|
|
225
|
-
if (isRequiredWithoutDefault) {
|
|
226
|
-
paramResult.isValid = false;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
return paramResult;
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Checks if the given API is supported.
|
|
233
|
-
* @param {string} method - The HTTP method of the API.
|
|
234
|
-
* @param {string} path - The path of the API.
|
|
235
|
-
* @param {OpenAPIV3.Document} spec - The OpenAPI specification document.
|
|
236
|
-
* @returns {boolean} - Returns true if the API is supported, false otherwise.
|
|
237
|
-
* @description The following APIs are supported:
|
|
238
|
-
* 1. only support Get/Post operation without auth property
|
|
239
|
-
* 2. parameter inside query or path only support string, number, boolean and integer
|
|
240
|
-
* 3. parameter inside post body only support string, number, boolean, integer and object
|
|
241
|
-
* 4. request body + required parameters <= 1
|
|
242
|
-
* 5. response body should be “application/json” and not empty, and response code should be 20X
|
|
243
|
-
* 6. only support request body with “application/json” content type
|
|
244
|
-
*/
|
|
245
|
-
static isSupportedApi(method, path, spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2) {
|
|
246
|
-
const pathObj = spec.paths[path];
|
|
247
|
-
method = method.toLocaleLowerCase();
|
|
248
|
-
if (pathObj) {
|
|
249
|
-
if ((method === ConstantString.PostMethod || method === ConstantString.GetMethod) &&
|
|
250
|
-
pathObj[method]) {
|
|
251
|
-
const securities = pathObj[method].security;
|
|
252
|
-
const authArray = Utils.getAuthArray(securities, spec);
|
|
253
|
-
if (!Utils.isSupportedAuth(authArray, allowAPIKeyAuth, allowOauth2)) {
|
|
254
|
-
return false;
|
|
255
|
-
}
|
|
256
|
-
const operationObject = pathObj[method];
|
|
257
|
-
if (!allowMissingId && !operationObject.operationId) {
|
|
258
|
-
return false;
|
|
259
|
-
}
|
|
260
|
-
const paramObject = operationObject.parameters;
|
|
261
|
-
const requestBody = operationObject.requestBody;
|
|
262
|
-
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
263
|
-
const mediaTypesCount = Object.keys((requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) || {}).length;
|
|
264
|
-
if (mediaTypesCount > 1) {
|
|
265
|
-
return false;
|
|
266
|
-
}
|
|
267
|
-
const responseJson = Utils.getResponseJson(operationObject);
|
|
268
|
-
if (Object.keys(responseJson).length === 0) {
|
|
269
|
-
return false;
|
|
270
|
-
}
|
|
271
|
-
let requestBodyParamResult = {
|
|
272
|
-
requiredNum: 0,
|
|
273
|
-
optionalNum: 0,
|
|
274
|
-
isValid: true,
|
|
275
|
-
};
|
|
276
|
-
if (requestJsonBody) {
|
|
277
|
-
const requestBodySchema = requestJsonBody.schema;
|
|
278
|
-
requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required);
|
|
279
|
-
}
|
|
280
|
-
if (!requestBodyParamResult.isValid) {
|
|
281
|
-
return false;
|
|
282
|
-
}
|
|
283
|
-
const paramResult = Utils.checkParameters(paramObject);
|
|
284
|
-
if (!paramResult.isValid) {
|
|
285
|
-
return false;
|
|
286
|
-
}
|
|
287
|
-
if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
|
|
288
|
-
if (allowMultipleParameters &&
|
|
289
|
-
requestBodyParamResult.requiredNum + paramResult.requiredNum <= 5) {
|
|
290
|
-
return true;
|
|
291
|
-
}
|
|
292
|
-
return false;
|
|
293
|
-
}
|
|
294
|
-
else if (requestBodyParamResult.requiredNum +
|
|
295
|
-
requestBodyParamResult.optionalNum +
|
|
296
|
-
paramResult.requiredNum +
|
|
297
|
-
paramResult.optionalNum ===
|
|
298
|
-
0) {
|
|
299
|
-
return false;
|
|
300
|
-
}
|
|
301
|
-
else {
|
|
177
|
+
static hasNestedObjectInSchema(schema) {
|
|
178
|
+
if (schema.type === "object") {
|
|
179
|
+
for (const property in schema.properties) {
|
|
180
|
+
const nestedSchema = schema.properties[property];
|
|
181
|
+
if (nestedSchema.type === "object") {
|
|
302
182
|
return true;
|
|
303
183
|
}
|
|
304
184
|
}
|
|
305
185
|
}
|
|
306
186
|
return false;
|
|
307
187
|
}
|
|
308
|
-
static
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
// Currently we don't support multiple auth in one operation
|
|
314
|
-
if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
|
|
315
|
-
return false;
|
|
316
|
-
}
|
|
317
|
-
for (const auths of authSchemaArray) {
|
|
318
|
-
if (auths.length === 1) {
|
|
319
|
-
if (!allowOauth2 && allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authSchema)) {
|
|
320
|
-
return true;
|
|
321
|
-
}
|
|
322
|
-
else if (!allowAPIKeyAuth &&
|
|
323
|
-
allowOauth2 &&
|
|
324
|
-
Utils.isBearerTokenAuth(auths[0].authSchema)) {
|
|
325
|
-
return true;
|
|
326
|
-
}
|
|
327
|
-
else if (allowAPIKeyAuth &&
|
|
328
|
-
allowOauth2 &&
|
|
329
|
-
(Utils.isAPIKeyAuth(auths[0].authSchema) ||
|
|
330
|
-
Utils.isBearerTokenAuth(auths[0].authSchema))) {
|
|
331
|
-
return true;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
return false;
|
|
188
|
+
static containMultipleMediaTypes(bodyObject) {
|
|
189
|
+
return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
|
|
190
|
+
}
|
|
191
|
+
static isBearerTokenAuth(authScheme) {
|
|
192
|
+
return authScheme.type === "http" && authScheme.scheme === "bearer";
|
|
337
193
|
}
|
|
338
|
-
static isAPIKeyAuth(
|
|
339
|
-
return
|
|
194
|
+
static isAPIKeyAuth(authScheme) {
|
|
195
|
+
return authScheme.type === "apiKey";
|
|
340
196
|
}
|
|
341
|
-
static
|
|
342
|
-
return (
|
|
343
|
-
|
|
344
|
-
|
|
197
|
+
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
198
|
+
return !!(authScheme.type === "oauth2" &&
|
|
199
|
+
authScheme.flows &&
|
|
200
|
+
authScheme.flows.authorizationCode);
|
|
345
201
|
}
|
|
346
202
|
static getAuthArray(securities, spec) {
|
|
347
203
|
var _a;
|
|
@@ -354,7 +210,7 @@ class Utils {
|
|
|
354
210
|
for (const name in security) {
|
|
355
211
|
const auth = securitySchemas[name];
|
|
356
212
|
authArray.push({
|
|
357
|
-
|
|
213
|
+
authScheme: auth,
|
|
358
214
|
name: name,
|
|
359
215
|
});
|
|
360
216
|
}
|
|
@@ -372,18 +228,22 @@ class Utils {
|
|
|
372
228
|
static getResponseJson(operationObject) {
|
|
373
229
|
var _a, _b;
|
|
374
230
|
let json = {};
|
|
231
|
+
let multipleMediaType = false;
|
|
375
232
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
376
233
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
377
|
-
const mediaTypesCount = Object.keys((responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) || {}).length;
|
|
378
|
-
if (mediaTypesCount > 1) {
|
|
379
|
-
return {};
|
|
380
|
-
}
|
|
381
234
|
if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
|
|
235
|
+
multipleMediaType = false;
|
|
382
236
|
json = responseObject.content["application/json"];
|
|
383
|
-
|
|
237
|
+
if (Utils.containMultipleMediaTypes(responseObject)) {
|
|
238
|
+
multipleMediaType = true;
|
|
239
|
+
json = {};
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
384
244
|
}
|
|
385
245
|
}
|
|
386
|
-
return json;
|
|
246
|
+
return { json, multipleMediaType };
|
|
387
247
|
}
|
|
388
248
|
static convertPathToCamelCase(path) {
|
|
389
249
|
const pathSegments = path.split(/[./{]/);
|
|
@@ -403,10 +263,10 @@ class Utils {
|
|
|
403
263
|
return undefined;
|
|
404
264
|
}
|
|
405
265
|
}
|
|
406
|
-
static
|
|
266
|
+
static resolveEnv(str) {
|
|
407
267
|
const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
|
|
408
|
-
let matches = placeHolderReg.exec(
|
|
409
|
-
let
|
|
268
|
+
let matches = placeHolderReg.exec(str);
|
|
269
|
+
let newStr = str;
|
|
410
270
|
while (matches != null) {
|
|
411
271
|
const envVar = matches[1];
|
|
412
272
|
const envVal = process.env[envVar];
|
|
@@ -414,17 +274,17 @@ class Utils {
|
|
|
414
274
|
throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
|
|
415
275
|
}
|
|
416
276
|
else {
|
|
417
|
-
|
|
277
|
+
newStr = newStr.replace(matches[0], envVal);
|
|
418
278
|
}
|
|
419
|
-
matches = placeHolderReg.exec(
|
|
279
|
+
matches = placeHolderReg.exec(str);
|
|
420
280
|
}
|
|
421
|
-
return
|
|
281
|
+
return newStr;
|
|
422
282
|
}
|
|
423
283
|
static checkServerUrl(servers) {
|
|
424
284
|
const errors = [];
|
|
425
285
|
let serverUrl;
|
|
426
286
|
try {
|
|
427
|
-
serverUrl = Utils.
|
|
287
|
+
serverUrl = Utils.resolveEnv(servers[0].url);
|
|
428
288
|
}
|
|
429
289
|
catch (err) {
|
|
430
290
|
errors.push({
|
|
@@ -454,7 +314,8 @@ class Utils {
|
|
|
454
314
|
}
|
|
455
315
|
return errors;
|
|
456
316
|
}
|
|
457
|
-
static validateServer(spec,
|
|
317
|
+
static validateServer(spec, options) {
|
|
318
|
+
var _a;
|
|
458
319
|
const errors = [];
|
|
459
320
|
let hasTopLevelServers = false;
|
|
460
321
|
let hasPathLevelServers = false;
|
|
@@ -475,7 +336,7 @@ class Utils {
|
|
|
475
336
|
}
|
|
476
337
|
for (const method in methods) {
|
|
477
338
|
const operationObject = methods[method];
|
|
478
|
-
if (
|
|
339
|
+
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
479
340
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
480
341
|
hasOperationLevelServers = true;
|
|
481
342
|
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
@@ -518,6 +379,7 @@ class Utils {
|
|
|
518
379
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
519
380
|
}
|
|
520
381
|
if (isRequired && schema.default === undefined) {
|
|
382
|
+
parameter.isRequired = true;
|
|
521
383
|
requiredParams.push(parameter);
|
|
522
384
|
}
|
|
523
385
|
else {
|
|
@@ -562,7 +424,7 @@ class Utils {
|
|
|
562
424
|
param.value = schema.default;
|
|
563
425
|
}
|
|
564
426
|
}
|
|
565
|
-
static parseApiInfo(operationItem,
|
|
427
|
+
static parseApiInfo(operationItem, options) {
|
|
566
428
|
var _a, _b;
|
|
567
429
|
const requiredParams = [];
|
|
568
430
|
const optionalParams = [];
|
|
@@ -576,11 +438,12 @@ class Utils {
|
|
|
576
438
|
description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
|
|
577
439
|
};
|
|
578
440
|
const schema = param.schema;
|
|
579
|
-
if (allowMultipleParameters && schema) {
|
|
441
|
+
if (options.allowMultipleParameters && schema) {
|
|
580
442
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
581
443
|
}
|
|
582
444
|
if (param.in !== "header" && param.in !== "cookie") {
|
|
583
445
|
if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
|
|
446
|
+
parameter.isRequired = true;
|
|
584
447
|
requiredParams.push(parameter);
|
|
585
448
|
}
|
|
586
449
|
else {
|
|
@@ -594,19 +457,13 @@ class Utils {
|
|
|
594
457
|
const requestJson = requestBody.content["application/json"];
|
|
595
458
|
if (Object.keys(requestJson).length !== 0) {
|
|
596
459
|
const schema = requestJson.schema;
|
|
597
|
-
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
|
|
460
|
+
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
|
|
598
461
|
requiredParams.push(...requiredP);
|
|
599
462
|
optionalParams.push(...optionalP);
|
|
600
463
|
}
|
|
601
464
|
}
|
|
602
465
|
const operationId = operationItem.operationId;
|
|
603
|
-
const parameters = [];
|
|
604
|
-
if (requiredParams.length !== 0) {
|
|
605
|
-
parameters.push(...requiredParams);
|
|
606
|
-
}
|
|
607
|
-
else {
|
|
608
|
-
parameters.push(optionalParams[0]);
|
|
609
|
-
}
|
|
466
|
+
const parameters = [...requiredParams, ...optionalParams];
|
|
610
467
|
const command = {
|
|
611
468
|
context: ["compose"],
|
|
612
469
|
type: "query",
|
|
@@ -615,105 +472,526 @@ class Utils {
|
|
|
615
472
|
parameters: parameters,
|
|
616
473
|
description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
|
|
617
474
|
};
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
475
|
+
return command;
|
|
476
|
+
}
|
|
477
|
+
static format(str, ...args) {
|
|
478
|
+
let index = 0;
|
|
479
|
+
return str.replace(/%s/g, () => {
|
|
480
|
+
const arg = args[index++];
|
|
481
|
+
return arg !== undefined ? arg : "";
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
static getSafeRegistrationIdEnvName(authName) {
|
|
485
|
+
if (!authName) {
|
|
486
|
+
return "";
|
|
487
|
+
}
|
|
488
|
+
let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
|
|
489
|
+
if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
|
|
490
|
+
safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
|
|
625
491
|
}
|
|
626
|
-
return
|
|
492
|
+
return safeRegistrationIdEnvName;
|
|
627
493
|
}
|
|
628
|
-
static
|
|
629
|
-
const
|
|
494
|
+
static getServerObject(spec, method, path) {
|
|
495
|
+
const pathObj = spec.paths[path];
|
|
496
|
+
const operationObject = pathObj[method];
|
|
497
|
+
const rootServer = spec.servers && spec.servers[0];
|
|
498
|
+
const methodServer = spec.paths[path].servers && spec.paths[path].servers[0];
|
|
499
|
+
const operationServer = operationObject.servers && operationObject.servers[0];
|
|
500
|
+
const serverUrl = operationServer || methodServer || rootServer;
|
|
501
|
+
return serverUrl;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Copyright (c) Microsoft Corporation.
|
|
506
|
+
class Validator {
|
|
507
|
+
listAPIs() {
|
|
508
|
+
var _a;
|
|
509
|
+
if (this.apiMap) {
|
|
510
|
+
return this.apiMap;
|
|
511
|
+
}
|
|
512
|
+
const paths = this.spec.paths;
|
|
630
513
|
const result = {};
|
|
631
514
|
for (const path in paths) {
|
|
632
515
|
const methods = paths[path];
|
|
633
516
|
for (const method in methods) {
|
|
634
|
-
|
|
635
|
-
if (
|
|
636
|
-
const
|
|
637
|
-
result[`${method.toUpperCase()} ${path}`] =
|
|
517
|
+
const operationObject = methods[method];
|
|
518
|
+
if (((_a = this.options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
519
|
+
const validateResult = this.validateAPI(method, path);
|
|
520
|
+
result[`${method.toUpperCase()} ${path}`] = {
|
|
521
|
+
operation: operationObject,
|
|
522
|
+
isValid: validateResult.isValid,
|
|
523
|
+
reason: validateResult.reason,
|
|
524
|
+
};
|
|
638
525
|
}
|
|
639
526
|
}
|
|
640
527
|
}
|
|
528
|
+
this.apiMap = result;
|
|
641
529
|
return result;
|
|
642
530
|
}
|
|
643
|
-
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
531
|
+
validateSpecVersion() {
|
|
532
|
+
const result = { errors: [], warnings: [] };
|
|
533
|
+
if (this.spec.openapi >= "3.1.0") {
|
|
534
|
+
result.errors.push({
|
|
535
|
+
type: ErrorType.SpecVersionNotSupported,
|
|
536
|
+
content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
|
|
537
|
+
data: this.spec.openapi,
|
|
650
538
|
});
|
|
651
539
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
const apiMap = Utils.listSupportedAPIs(spec, allowMissingId, allowAPIKeyAuth, allowMultipleParameters, allowOauth2);
|
|
667
|
-
if (Object.keys(apiMap).length === 0) {
|
|
668
|
-
errors.push({
|
|
540
|
+
return result;
|
|
541
|
+
}
|
|
542
|
+
validateSpecServer() {
|
|
543
|
+
const result = { errors: [], warnings: [] };
|
|
544
|
+
const serverErrors = Utils.validateServer(this.spec, this.options);
|
|
545
|
+
result.errors.push(...serverErrors);
|
|
546
|
+
return result;
|
|
547
|
+
}
|
|
548
|
+
validateSpecNoSupportAPI() {
|
|
549
|
+
const result = { errors: [], warnings: [] };
|
|
550
|
+
const apiMap = this.listAPIs();
|
|
551
|
+
const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
|
|
552
|
+
if (validAPIs.length === 0) {
|
|
553
|
+
result.errors.push({
|
|
669
554
|
type: ErrorType.NoSupportedApi,
|
|
670
555
|
content: ConstantString.NoSupportedApi,
|
|
671
556
|
});
|
|
672
557
|
}
|
|
558
|
+
return result;
|
|
559
|
+
}
|
|
560
|
+
validateSpecOperationId() {
|
|
561
|
+
const result = { errors: [], warnings: [] };
|
|
562
|
+
const apiMap = this.listAPIs();
|
|
673
563
|
// OperationId missing
|
|
674
564
|
const apisMissingOperationId = [];
|
|
675
565
|
for (const key in apiMap) {
|
|
676
|
-
const
|
|
677
|
-
if (!
|
|
566
|
+
const { operation } = apiMap[key];
|
|
567
|
+
if (!operation.operationId) {
|
|
678
568
|
apisMissingOperationId.push(key);
|
|
679
569
|
}
|
|
680
570
|
}
|
|
681
571
|
if (apisMissingOperationId.length > 0) {
|
|
682
|
-
warnings.push({
|
|
572
|
+
result.warnings.push({
|
|
683
573
|
type: WarningType.OperationIdMissing,
|
|
684
574
|
content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
|
|
685
575
|
data: apisMissingOperationId,
|
|
686
576
|
});
|
|
687
577
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
578
|
+
return result;
|
|
579
|
+
}
|
|
580
|
+
validateMethodAndPath(method, path) {
|
|
581
|
+
const result = { isValid: true, reason: [] };
|
|
582
|
+
if (this.options.allowMethods && !this.options.allowMethods.includes(method)) {
|
|
583
|
+
result.isValid = false;
|
|
584
|
+
result.reason.push(ErrorType.MethodNotAllowed);
|
|
585
|
+
return result;
|
|
691
586
|
}
|
|
692
|
-
|
|
693
|
-
|
|
587
|
+
const pathObj = this.spec.paths[path];
|
|
588
|
+
if (!pathObj || !pathObj[method]) {
|
|
589
|
+
result.isValid = false;
|
|
590
|
+
result.reason.push(ErrorType.UrlPathNotExist);
|
|
591
|
+
return result;
|
|
694
592
|
}
|
|
695
|
-
return
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
593
|
+
return result;
|
|
594
|
+
}
|
|
595
|
+
validateResponse(method, path) {
|
|
596
|
+
const result = { isValid: true, reason: [] };
|
|
597
|
+
const operationObject = this.spec.paths[path][method];
|
|
598
|
+
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
599
|
+
// only support response body only contains “application/json” content type
|
|
600
|
+
if (multipleMediaType) {
|
|
601
|
+
result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
|
|
602
|
+
}
|
|
603
|
+
else if (Object.keys(json).length === 0) {
|
|
604
|
+
// response body should not be empty
|
|
605
|
+
result.reason.push(ErrorType.ResponseJsonIsEmpty);
|
|
606
|
+
}
|
|
607
|
+
return result;
|
|
608
|
+
}
|
|
609
|
+
validateServer(method, path) {
|
|
610
|
+
const result = { isValid: true, reason: [] };
|
|
611
|
+
const serverObj = Utils.getServerObject(this.spec, method, path);
|
|
612
|
+
if (!serverObj) {
|
|
613
|
+
// should contain server URL
|
|
614
|
+
result.reason.push(ErrorType.NoServerInformation);
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
// server url should be absolute url with https protocol
|
|
618
|
+
const serverValidateResult = Utils.checkServerUrl([serverObj]);
|
|
619
|
+
result.reason.push(...serverValidateResult.map((item) => item.type));
|
|
620
|
+
}
|
|
621
|
+
return result;
|
|
622
|
+
}
|
|
623
|
+
validateAuth(method, path) {
|
|
624
|
+
const pathObj = this.spec.paths[path];
|
|
625
|
+
const operationObject = pathObj[method];
|
|
626
|
+
const securities = operationObject.security;
|
|
627
|
+
const authSchemeArray = Utils.getAuthArray(securities, this.spec);
|
|
628
|
+
if (authSchemeArray.length === 0) {
|
|
629
|
+
return { isValid: true, reason: [] };
|
|
630
|
+
}
|
|
631
|
+
if (this.options.allowAPIKeyAuth ||
|
|
632
|
+
this.options.allowOauth2 ||
|
|
633
|
+
this.options.allowBearerTokenAuth) {
|
|
634
|
+
// Currently we don't support multiple auth in one operation
|
|
635
|
+
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
636
|
+
return {
|
|
637
|
+
isValid: false,
|
|
638
|
+
reason: [ErrorType.MultipleAuthNotSupported],
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
for (const auths of authSchemeArray) {
|
|
642
|
+
if (auths.length === 1) {
|
|
643
|
+
if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
644
|
+
(this.options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
|
|
645
|
+
(this.options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
|
|
646
|
+
return { isValid: true, reason: [] };
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
|
|
652
|
+
}
|
|
653
|
+
checkPostBodySchema(schema, isRequired = false) {
|
|
654
|
+
var _a;
|
|
655
|
+
const paramResult = {
|
|
656
|
+
requiredNum: 0,
|
|
657
|
+
optionalNum: 0,
|
|
658
|
+
isValid: true,
|
|
659
|
+
reason: [],
|
|
699
660
|
};
|
|
661
|
+
if (Object.keys(schema).length === 0) {
|
|
662
|
+
return paramResult;
|
|
663
|
+
}
|
|
664
|
+
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
665
|
+
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
666
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
667
|
+
paramResult.isValid = false;
|
|
668
|
+
paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
|
|
669
|
+
return paramResult;
|
|
670
|
+
}
|
|
671
|
+
if (schema.type === "string" ||
|
|
672
|
+
schema.type === "integer" ||
|
|
673
|
+
schema.type === "boolean" ||
|
|
674
|
+
schema.type === "number") {
|
|
675
|
+
if (isRequiredWithoutDefault) {
|
|
676
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
else if (schema.type === "object") {
|
|
683
|
+
const { properties } = schema;
|
|
684
|
+
for (const property in properties) {
|
|
685
|
+
let isRequired = false;
|
|
686
|
+
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
687
|
+
isRequired = true;
|
|
688
|
+
}
|
|
689
|
+
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
690
|
+
paramResult.requiredNum += result.requiredNum;
|
|
691
|
+
paramResult.optionalNum += result.optionalNum;
|
|
692
|
+
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
693
|
+
paramResult.reason.push(...result.reason);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
698
|
+
paramResult.isValid = false;
|
|
699
|
+
paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
return paramResult;
|
|
700
703
|
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
704
|
+
checkParamSchema(paramObject) {
|
|
705
|
+
const paramResult = {
|
|
706
|
+
requiredNum: 0,
|
|
707
|
+
optionalNum: 0,
|
|
708
|
+
isValid: true,
|
|
709
|
+
reason: [],
|
|
710
|
+
};
|
|
711
|
+
if (!paramObject) {
|
|
712
|
+
return paramResult;
|
|
713
|
+
}
|
|
714
|
+
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
715
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
716
|
+
const param = paramObject[i];
|
|
717
|
+
const schema = param.schema;
|
|
718
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
719
|
+
paramResult.isValid = false;
|
|
720
|
+
paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
724
|
+
if (isCopilot) {
|
|
725
|
+
if (isRequiredWithoutDefault) {
|
|
726
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
727
|
+
}
|
|
728
|
+
else {
|
|
729
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
730
|
+
}
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
if (param.in === "header" || param.in === "cookie") {
|
|
734
|
+
if (isRequiredWithoutDefault) {
|
|
735
|
+
paramResult.isValid = false;
|
|
736
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
737
|
+
}
|
|
738
|
+
continue;
|
|
739
|
+
}
|
|
740
|
+
if (schema.type !== "boolean" &&
|
|
741
|
+
schema.type !== "string" &&
|
|
742
|
+
schema.type !== "number" &&
|
|
743
|
+
schema.type !== "integer") {
|
|
744
|
+
if (isRequiredWithoutDefault) {
|
|
745
|
+
paramResult.isValid = false;
|
|
746
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
747
|
+
}
|
|
748
|
+
continue;
|
|
749
|
+
}
|
|
750
|
+
if (param.in === "query" || param.in === "path") {
|
|
751
|
+
if (isRequiredWithoutDefault) {
|
|
752
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
753
|
+
}
|
|
754
|
+
else {
|
|
755
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return paramResult;
|
|
707
760
|
}
|
|
708
|
-
|
|
709
|
-
if (
|
|
710
|
-
|
|
761
|
+
hasNestedObjectInSchema(schema) {
|
|
762
|
+
if (schema.type === "object") {
|
|
763
|
+
for (const property in schema.properties) {
|
|
764
|
+
const nestedSchema = schema.properties[property];
|
|
765
|
+
if (nestedSchema.type === "object") {
|
|
766
|
+
return true;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
711
769
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
770
|
+
return false;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// Copyright (c) Microsoft Corporation.
|
|
775
|
+
class CopilotValidator extends Validator {
|
|
776
|
+
constructor(spec, options) {
|
|
777
|
+
super();
|
|
778
|
+
this.projectType = ProjectType.Copilot;
|
|
779
|
+
this.options = options;
|
|
780
|
+
this.spec = spec;
|
|
781
|
+
}
|
|
782
|
+
validateSpec() {
|
|
783
|
+
const result = { errors: [], warnings: [] };
|
|
784
|
+
// validate spec version
|
|
785
|
+
let validationResult = this.validateSpecVersion();
|
|
786
|
+
result.errors.push(...validationResult.errors);
|
|
787
|
+
// validate spec server
|
|
788
|
+
validationResult = this.validateSpecServer();
|
|
789
|
+
result.errors.push(...validationResult.errors);
|
|
790
|
+
// validate no supported API
|
|
791
|
+
validationResult = this.validateSpecNoSupportAPI();
|
|
792
|
+
result.errors.push(...validationResult.errors);
|
|
793
|
+
// validate operationId missing
|
|
794
|
+
validationResult = this.validateSpecOperationId();
|
|
795
|
+
result.warnings.push(...validationResult.warnings);
|
|
796
|
+
return result;
|
|
797
|
+
}
|
|
798
|
+
validateAPI(method, path) {
|
|
799
|
+
const result = { isValid: true, reason: [] };
|
|
800
|
+
method = method.toLocaleLowerCase();
|
|
801
|
+
// validate method and path
|
|
802
|
+
const methodAndPathResult = this.validateMethodAndPath(method, path);
|
|
803
|
+
if (!methodAndPathResult.isValid) {
|
|
804
|
+
return methodAndPathResult;
|
|
805
|
+
}
|
|
806
|
+
const operationObject = this.spec.paths[path][method];
|
|
807
|
+
// validate auth
|
|
808
|
+
const authCheckResult = this.validateAuth(method, path);
|
|
809
|
+
result.reason.push(...authCheckResult.reason);
|
|
810
|
+
// validate operationId
|
|
811
|
+
if (!this.options.allowMissingId && !operationObject.operationId) {
|
|
812
|
+
result.reason.push(ErrorType.MissingOperationId);
|
|
813
|
+
}
|
|
814
|
+
// validate server
|
|
815
|
+
const validateServerResult = this.validateServer(method, path);
|
|
816
|
+
result.reason.push(...validateServerResult.reason);
|
|
817
|
+
// validate response
|
|
818
|
+
const validateResponseResult = this.validateResponse(method, path);
|
|
819
|
+
result.reason.push(...validateResponseResult.reason);
|
|
820
|
+
// validate requestBody
|
|
821
|
+
const requestBody = operationObject.requestBody;
|
|
822
|
+
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
823
|
+
if (Utils.containMultipleMediaTypes(requestBody)) {
|
|
824
|
+
result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
|
|
825
|
+
}
|
|
826
|
+
if (requestJsonBody) {
|
|
827
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
828
|
+
if (requestBodySchema.type !== "object") {
|
|
829
|
+
result.reason.push(ErrorType.PostBodySchemaIsNotJson);
|
|
830
|
+
}
|
|
831
|
+
const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
|
|
832
|
+
result.reason.push(...requestBodyParamResult.reason);
|
|
833
|
+
}
|
|
834
|
+
// validate parameters
|
|
835
|
+
const paramObject = operationObject.parameters;
|
|
836
|
+
const paramResult = this.checkParamSchema(paramObject);
|
|
837
|
+
result.reason.push(...paramResult.reason);
|
|
838
|
+
if (result.reason.length > 0) {
|
|
839
|
+
result.isValid = false;
|
|
840
|
+
}
|
|
841
|
+
return result;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Copyright (c) Microsoft Corporation.
|
|
846
|
+
class SMEValidator extends Validator {
|
|
847
|
+
constructor(spec, options) {
|
|
848
|
+
super();
|
|
849
|
+
this.projectType = ProjectType.SME;
|
|
850
|
+
this.options = options;
|
|
851
|
+
this.spec = spec;
|
|
852
|
+
}
|
|
853
|
+
validateSpec() {
|
|
854
|
+
const result = { errors: [], warnings: [] };
|
|
855
|
+
// validate spec version
|
|
856
|
+
let validationResult = this.validateSpecVersion();
|
|
857
|
+
result.errors.push(...validationResult.errors);
|
|
858
|
+
// validate spec server
|
|
859
|
+
validationResult = this.validateSpecServer();
|
|
860
|
+
result.errors.push(...validationResult.errors);
|
|
861
|
+
// validate no supported API
|
|
862
|
+
validationResult = this.validateSpecNoSupportAPI();
|
|
863
|
+
result.errors.push(...validationResult.errors);
|
|
864
|
+
// validate operationId missing
|
|
865
|
+
validationResult = this.validateSpecOperationId();
|
|
866
|
+
result.warnings.push(...validationResult.warnings);
|
|
867
|
+
return result;
|
|
868
|
+
}
|
|
869
|
+
validateAPI(method, path) {
|
|
870
|
+
const result = { isValid: true, reason: [] };
|
|
871
|
+
method = method.toLocaleLowerCase();
|
|
872
|
+
// validate method and path
|
|
873
|
+
const methodAndPathResult = this.validateMethodAndPath(method, path);
|
|
874
|
+
if (!methodAndPathResult.isValid) {
|
|
875
|
+
return methodAndPathResult;
|
|
876
|
+
}
|
|
877
|
+
const operationObject = this.spec.paths[path][method];
|
|
878
|
+
// validate auth
|
|
879
|
+
const authCheckResult = this.validateAuth(method, path);
|
|
880
|
+
result.reason.push(...authCheckResult.reason);
|
|
881
|
+
// validate operationId
|
|
882
|
+
if (!this.options.allowMissingId && !operationObject.operationId) {
|
|
883
|
+
result.reason.push(ErrorType.MissingOperationId);
|
|
884
|
+
}
|
|
885
|
+
// validate server
|
|
886
|
+
const validateServerResult = this.validateServer(method, path);
|
|
887
|
+
result.reason.push(...validateServerResult.reason);
|
|
888
|
+
// validate response
|
|
889
|
+
const validateResponseResult = this.validateResponse(method, path);
|
|
890
|
+
result.reason.push(...validateResponseResult.reason);
|
|
891
|
+
let postBodyResult = {
|
|
892
|
+
requiredNum: 0,
|
|
893
|
+
optionalNum: 0,
|
|
894
|
+
isValid: true,
|
|
895
|
+
reason: [],
|
|
896
|
+
};
|
|
897
|
+
// validate requestBody
|
|
898
|
+
const requestBody = operationObject.requestBody;
|
|
899
|
+
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
900
|
+
if (Utils.containMultipleMediaTypes(requestBody)) {
|
|
901
|
+
result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
|
|
902
|
+
}
|
|
903
|
+
if (requestJsonBody) {
|
|
904
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
905
|
+
postBodyResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
|
|
906
|
+
result.reason.push(...postBodyResult.reason);
|
|
907
|
+
}
|
|
908
|
+
// validate parameters
|
|
909
|
+
const paramObject = operationObject.parameters;
|
|
910
|
+
const paramResult = this.checkParamSchema(paramObject);
|
|
911
|
+
result.reason.push(...paramResult.reason);
|
|
912
|
+
// validate total parameters count
|
|
913
|
+
if (paramResult.isValid && postBodyResult.isValid) {
|
|
914
|
+
const paramCountResult = this.validateParamCount(postBodyResult, paramResult);
|
|
915
|
+
result.reason.push(...paramCountResult.reason);
|
|
916
|
+
}
|
|
917
|
+
if (result.reason.length > 0) {
|
|
918
|
+
result.isValid = false;
|
|
919
|
+
}
|
|
920
|
+
return result;
|
|
921
|
+
}
|
|
922
|
+
validateParamCount(postBodyResult, paramResult) {
|
|
923
|
+
const result = { isValid: true, reason: [] };
|
|
924
|
+
const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
|
|
925
|
+
const totalParams = totalRequiredParams + postBodyResult.optionalNum + paramResult.optionalNum;
|
|
926
|
+
if (totalRequiredParams > 1) {
|
|
927
|
+
if (!this.options.allowMultipleParameters ||
|
|
928
|
+
totalRequiredParams > SMEValidator.SMERequiredParamsMaxNum) {
|
|
929
|
+
result.reason.push(ErrorType.ExceededRequiredParamsLimit);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
else if (totalParams === 0) {
|
|
933
|
+
result.reason.push(ErrorType.NoParameter);
|
|
934
|
+
}
|
|
935
|
+
return result;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
SMEValidator.SMERequiredParamsMaxNum = 5;
|
|
939
|
+
|
|
940
|
+
// Copyright (c) Microsoft Corporation.
|
|
941
|
+
class TeamsAIValidator extends Validator {
|
|
942
|
+
constructor(spec, options) {
|
|
943
|
+
super();
|
|
944
|
+
this.projectType = ProjectType.TeamsAi;
|
|
945
|
+
this.options = options;
|
|
946
|
+
this.spec = spec;
|
|
947
|
+
}
|
|
948
|
+
validateSpec() {
|
|
949
|
+
const result = { errors: [], warnings: [] };
|
|
950
|
+
// validate spec server
|
|
951
|
+
let validationResult = this.validateSpecServer();
|
|
952
|
+
result.errors.push(...validationResult.errors);
|
|
953
|
+
// validate no supported API
|
|
954
|
+
validationResult = this.validateSpecNoSupportAPI();
|
|
955
|
+
result.errors.push(...validationResult.errors);
|
|
956
|
+
return result;
|
|
957
|
+
}
|
|
958
|
+
validateAPI(method, path) {
|
|
959
|
+
const result = { isValid: true, reason: [] };
|
|
960
|
+
method = method.toLocaleLowerCase();
|
|
961
|
+
// validate method and path
|
|
962
|
+
const methodAndPathResult = this.validateMethodAndPath(method, path);
|
|
963
|
+
if (!methodAndPathResult.isValid) {
|
|
964
|
+
return methodAndPathResult;
|
|
965
|
+
}
|
|
966
|
+
const operationObject = this.spec.paths[path][method];
|
|
967
|
+
// validate operationId
|
|
968
|
+
if (!this.options.allowMissingId && !operationObject.operationId) {
|
|
969
|
+
result.reason.push(ErrorType.MissingOperationId);
|
|
970
|
+
}
|
|
971
|
+
// validate server
|
|
972
|
+
const validateServerResult = this.validateServer(method, path);
|
|
973
|
+
result.reason.push(...validateServerResult.reason);
|
|
974
|
+
if (result.reason.length > 0) {
|
|
975
|
+
result.isValid = false;
|
|
976
|
+
}
|
|
977
|
+
return result;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
class ValidatorFactory {
|
|
982
|
+
static create(spec, options) {
|
|
983
|
+
var _a;
|
|
984
|
+
const type = (_a = options.projectType) !== null && _a !== void 0 ? _a : ProjectType.SME;
|
|
985
|
+
switch (type) {
|
|
986
|
+
case ProjectType.SME:
|
|
987
|
+
return new SMEValidator(spec, options);
|
|
988
|
+
case ProjectType.Copilot:
|
|
989
|
+
return new CopilotValidator(spec, options);
|
|
990
|
+
case ProjectType.TeamsAi:
|
|
991
|
+
return new TeamsAIValidator(spec, options);
|
|
992
|
+
default:
|
|
993
|
+
throw new Error(`Invalid project type: ${type}`);
|
|
715
994
|
}
|
|
716
|
-
return safeRegistrationIdEnvName;
|
|
717
995
|
}
|
|
718
996
|
}
|
|
719
997
|
|
|
@@ -733,7 +1011,10 @@ class SpecParser {
|
|
|
733
1011
|
allowSwagger: false,
|
|
734
1012
|
allowAPIKeyAuth: false,
|
|
735
1013
|
allowMultipleParameters: false,
|
|
1014
|
+
allowBearerTokenAuth: false,
|
|
736
1015
|
allowOauth2: false,
|
|
1016
|
+
allowMethods: ["get", "post"],
|
|
1017
|
+
projectType: ProjectType.SME,
|
|
737
1018
|
};
|
|
738
1019
|
this.pathOrSpec = pathOrDoc;
|
|
739
1020
|
this.parser = new SwaggerParser();
|
|
@@ -748,11 +1029,7 @@ class SpecParser {
|
|
|
748
1029
|
try {
|
|
749
1030
|
try {
|
|
750
1031
|
await this.loadSpec();
|
|
751
|
-
await this.parser.validate(this.spec
|
|
752
|
-
validate: {
|
|
753
|
-
schema: false,
|
|
754
|
-
},
|
|
755
|
-
});
|
|
1032
|
+
await this.parser.validate(this.spec);
|
|
756
1033
|
}
|
|
757
1034
|
catch (e) {
|
|
758
1035
|
return {
|
|
@@ -761,16 +1038,46 @@ class SpecParser {
|
|
|
761
1038
|
errors: [{ type: ErrorType.SpecNotValid, content: e.toString() }],
|
|
762
1039
|
};
|
|
763
1040
|
}
|
|
1041
|
+
const errors = [];
|
|
1042
|
+
const warnings = [];
|
|
764
1043
|
if (!this.options.allowSwagger && this.isSwaggerFile) {
|
|
765
1044
|
return {
|
|
766
1045
|
status: ValidationStatus.Error,
|
|
767
1046
|
warnings: [],
|
|
768
1047
|
errors: [
|
|
769
|
-
{
|
|
1048
|
+
{
|
|
1049
|
+
type: ErrorType.SwaggerNotSupported,
|
|
1050
|
+
content: ConstantString.SwaggerNotSupported,
|
|
1051
|
+
},
|
|
770
1052
|
],
|
|
771
1053
|
};
|
|
772
1054
|
}
|
|
773
|
-
|
|
1055
|
+
// Remote reference not supported
|
|
1056
|
+
const refPaths = this.parser.$refs.paths();
|
|
1057
|
+
// refPaths [0] is the current spec file path
|
|
1058
|
+
if (refPaths.length > 1) {
|
|
1059
|
+
errors.push({
|
|
1060
|
+
type: ErrorType.RemoteRefNotSupported,
|
|
1061
|
+
content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
|
|
1062
|
+
data: refPaths,
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
const validator = this.getValidator(this.spec);
|
|
1066
|
+
const validationResult = validator.validateSpec();
|
|
1067
|
+
warnings.push(...validationResult.warnings);
|
|
1068
|
+
errors.push(...validationResult.errors);
|
|
1069
|
+
let status = ValidationStatus.Valid;
|
|
1070
|
+
if (warnings.length > 0 && errors.length === 0) {
|
|
1071
|
+
status = ValidationStatus.Warning;
|
|
1072
|
+
}
|
|
1073
|
+
else if (errors.length > 0) {
|
|
1074
|
+
status = ValidationStatus.Error;
|
|
1075
|
+
}
|
|
1076
|
+
return {
|
|
1077
|
+
status: status,
|
|
1078
|
+
warnings: warnings,
|
|
1079
|
+
errors: errors,
|
|
1080
|
+
};
|
|
774
1081
|
}
|
|
775
1082
|
catch (err) {
|
|
776
1083
|
throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
|
|
@@ -779,17 +1086,20 @@ class SpecParser {
|
|
|
779
1086
|
async listSupportedAPIInfo() {
|
|
780
1087
|
try {
|
|
781
1088
|
await this.loadSpec();
|
|
782
|
-
const apiMap = this.
|
|
1089
|
+
const apiMap = this.getAPIs(this.spec);
|
|
783
1090
|
const apiInfos = [];
|
|
784
1091
|
for (const key in apiMap) {
|
|
785
|
-
const
|
|
1092
|
+
const { operation, isValid } = apiMap[key];
|
|
1093
|
+
if (!isValid) {
|
|
1094
|
+
continue;
|
|
1095
|
+
}
|
|
786
1096
|
const [method, path] = key.split(" ");
|
|
787
|
-
const operationId =
|
|
1097
|
+
const operationId = operation.operationId;
|
|
788
1098
|
// In Browser environment, this api is by default not support api without operationId
|
|
789
1099
|
if (!operationId) {
|
|
790
1100
|
continue;
|
|
791
1101
|
}
|
|
792
|
-
const
|
|
1102
|
+
const command = Utils.parseApiInfo(operation, this.options);
|
|
793
1103
|
const apiInfo = {
|
|
794
1104
|
method: method,
|
|
795
1105
|
path: path,
|
|
@@ -798,9 +1108,6 @@ class SpecParser {
|
|
|
798
1108
|
parameters: command.parameters,
|
|
799
1109
|
description: command.description,
|
|
800
1110
|
};
|
|
801
|
-
if (warning) {
|
|
802
|
-
apiInfo.warning = warning;
|
|
803
|
-
}
|
|
804
1111
|
apiInfos.push(apiInfo);
|
|
805
1112
|
}
|
|
806
1113
|
return apiInfos;
|
|
@@ -818,12 +1125,32 @@ class SpecParser {
|
|
|
818
1125
|
async list() {
|
|
819
1126
|
throw new Error("Method not implemented.");
|
|
820
1127
|
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Generate specs according to the filters.
|
|
1130
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
1131
|
+
*/
|
|
1132
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
1133
|
+
async getFilteredSpecs(filter, signal) {
|
|
1134
|
+
throw new Error("Method not implemented.");
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
1138
|
+
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
1139
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
1140
|
+
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
1141
|
+
* @param pluginFilePath File path of the api plugin file to generate.
|
|
1142
|
+
*/
|
|
1143
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
1144
|
+
async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
|
|
1145
|
+
throw new Error("Method not implemented.");
|
|
1146
|
+
}
|
|
821
1147
|
/**
|
|
822
1148
|
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
823
1149
|
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
824
1150
|
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
825
1151
|
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
826
1152
|
* @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
|
|
1153
|
+
* @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
|
|
827
1154
|
*/
|
|
828
1155
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
829
1156
|
async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
|
|
@@ -839,15 +1166,182 @@ class SpecParser {
|
|
|
839
1166
|
this.spec = (await this.parser.dereference(clonedUnResolveSpec));
|
|
840
1167
|
}
|
|
841
1168
|
}
|
|
842
|
-
|
|
1169
|
+
getAPIs(spec) {
|
|
843
1170
|
if (this.apiMap !== undefined) {
|
|
844
1171
|
return this.apiMap;
|
|
845
1172
|
}
|
|
846
|
-
const
|
|
847
|
-
|
|
848
|
-
|
|
1173
|
+
const validator = this.getValidator(spec);
|
|
1174
|
+
const apiMap = validator.listAPIs();
|
|
1175
|
+
this.apiMap = apiMap;
|
|
1176
|
+
return apiMap;
|
|
1177
|
+
}
|
|
1178
|
+
getValidator(spec) {
|
|
1179
|
+
if (this.validator) {
|
|
1180
|
+
return this.validator;
|
|
1181
|
+
}
|
|
1182
|
+
const validator = ValidatorFactory.create(spec, this.options);
|
|
1183
|
+
this.validator = validator;
|
|
1184
|
+
return validator;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
// Copyright (c) Microsoft Corporation.
|
|
1189
|
+
class AdaptiveCardGenerator {
|
|
1190
|
+
static generateAdaptiveCard(operationItem) {
|
|
1191
|
+
try {
|
|
1192
|
+
const { json } = Utils.getResponseJson(operationItem);
|
|
1193
|
+
let cardBody = [];
|
|
1194
|
+
let schema = json.schema;
|
|
1195
|
+
let jsonPath = "$";
|
|
1196
|
+
if (schema && Object.keys(schema).length > 0) {
|
|
1197
|
+
jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
|
|
1198
|
+
if (jsonPath !== "$") {
|
|
1199
|
+
schema = schema.properties[jsonPath];
|
|
1200
|
+
}
|
|
1201
|
+
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
|
|
1202
|
+
}
|
|
1203
|
+
// if no schema, try to use example value
|
|
1204
|
+
if (cardBody.length === 0 && (json.examples || json.example)) {
|
|
1205
|
+
cardBody = [
|
|
1206
|
+
{
|
|
1207
|
+
type: ConstantString.TextBlockType,
|
|
1208
|
+
text: "${jsonStringify($root)}",
|
|
1209
|
+
wrap: true,
|
|
1210
|
+
},
|
|
1211
|
+
];
|
|
1212
|
+
}
|
|
1213
|
+
// if no example value, use default success response
|
|
1214
|
+
if (cardBody.length === 0) {
|
|
1215
|
+
cardBody = [
|
|
1216
|
+
{
|
|
1217
|
+
type: ConstantString.TextBlockType,
|
|
1218
|
+
text: "success",
|
|
1219
|
+
wrap: true,
|
|
1220
|
+
},
|
|
1221
|
+
];
|
|
1222
|
+
}
|
|
1223
|
+
const fullCard = {
|
|
1224
|
+
type: ConstantString.AdaptiveCardType,
|
|
1225
|
+
$schema: ConstantString.AdaptiveCardSchema,
|
|
1226
|
+
version: ConstantString.AdaptiveCardVersion,
|
|
1227
|
+
body: cardBody,
|
|
1228
|
+
};
|
|
1229
|
+
return [fullCard, jsonPath];
|
|
1230
|
+
}
|
|
1231
|
+
catch (err) {
|
|
1232
|
+
throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
static generateCardFromResponse(schema, name, parentArrayName = "") {
|
|
1236
|
+
if (schema.type === "array") {
|
|
1237
|
+
// schema.items can be arbitrary object: schema { type: array, items: {} }
|
|
1238
|
+
if (Object.keys(schema.items).length === 0) {
|
|
1239
|
+
return [
|
|
1240
|
+
{
|
|
1241
|
+
type: ConstantString.TextBlockType,
|
|
1242
|
+
text: name ? `${name}: \${jsonStringify(${name})}` : "result: ${jsonStringify($root)}",
|
|
1243
|
+
wrap: true,
|
|
1244
|
+
},
|
|
1245
|
+
];
|
|
1246
|
+
}
|
|
1247
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
|
|
1248
|
+
const template = {
|
|
1249
|
+
type: ConstantString.ContainerType,
|
|
1250
|
+
$data: name ? `\${${name}}` : "${$root}",
|
|
1251
|
+
items: Array(),
|
|
1252
|
+
};
|
|
1253
|
+
template.items.push(...obj);
|
|
1254
|
+
return [template];
|
|
1255
|
+
}
|
|
1256
|
+
// some schema may not contain type but contain properties
|
|
1257
|
+
if (schema.type === "object" || (!schema.type && schema.properties)) {
|
|
1258
|
+
const { properties } = schema;
|
|
1259
|
+
const result = [];
|
|
1260
|
+
for (const property in properties) {
|
|
1261
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
|
|
1262
|
+
result.push(...obj);
|
|
1263
|
+
}
|
|
1264
|
+
if (schema.additionalProperties) {
|
|
1265
|
+
// TODO: better ways to handler warnings.
|
|
1266
|
+
console.warn(ConstantString.AdditionalPropertiesNotSupported);
|
|
1267
|
+
}
|
|
1268
|
+
return result;
|
|
1269
|
+
}
|
|
1270
|
+
if (schema.type === "string" ||
|
|
1271
|
+
schema.type === "integer" ||
|
|
1272
|
+
schema.type === "boolean" ||
|
|
1273
|
+
schema.type === "number") {
|
|
1274
|
+
if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
|
|
1275
|
+
// string in root: "ddd"
|
|
1276
|
+
let text = "result: ${$root}";
|
|
1277
|
+
if (name) {
|
|
1278
|
+
// object { id: "1" }
|
|
1279
|
+
text = `${name}: \${if(${name}, ${name}, 'N/A')}`;
|
|
1280
|
+
if (parentArrayName) {
|
|
1281
|
+
// object types inside array: { tags: ["id": 1, "name": "name"] }
|
|
1282
|
+
text = `${parentArrayName}.${text}`;
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
else if (parentArrayName) {
|
|
1286
|
+
// string array: photoUrls: ["1", "2"]
|
|
1287
|
+
text = `${parentArrayName}: ` + "${$data}";
|
|
1288
|
+
}
|
|
1289
|
+
return [
|
|
1290
|
+
{
|
|
1291
|
+
type: ConstantString.TextBlockType,
|
|
1292
|
+
text,
|
|
1293
|
+
wrap: true,
|
|
1294
|
+
},
|
|
1295
|
+
];
|
|
1296
|
+
}
|
|
1297
|
+
else {
|
|
1298
|
+
if (name) {
|
|
1299
|
+
return [
|
|
1300
|
+
{
|
|
1301
|
+
type: "Image",
|
|
1302
|
+
url: `\${${name}}`,
|
|
1303
|
+
$when: `\${${name} != null}`,
|
|
1304
|
+
},
|
|
1305
|
+
];
|
|
1306
|
+
}
|
|
1307
|
+
else {
|
|
1308
|
+
return [
|
|
1309
|
+
{
|
|
1310
|
+
type: "Image",
|
|
1311
|
+
url: "${$data}",
|
|
1312
|
+
$when: "${$data != null}",
|
|
1313
|
+
},
|
|
1314
|
+
];
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
|
|
1319
|
+
throw new Error(Utils.format(ConstantString.SchemaNotSupported, JSON.stringify(schema)));
|
|
1320
|
+
}
|
|
1321
|
+
throw new Error(Utils.format(ConstantString.UnknownSchema, JSON.stringify(schema)));
|
|
1322
|
+
}
|
|
1323
|
+
// Find the first array property in the response schema object with the well-known name
|
|
1324
|
+
static getResponseJsonPathFromSchema(schema) {
|
|
1325
|
+
if (schema.type === "object" || (!schema.type && schema.properties)) {
|
|
1326
|
+
const { properties } = schema;
|
|
1327
|
+
for (const property in properties) {
|
|
1328
|
+
const schema = properties[property];
|
|
1329
|
+
if (schema.type === "array" &&
|
|
1330
|
+
Utils.isWellKnownName(property, ConstantString.WellknownResultNames)) {
|
|
1331
|
+
return property;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
return "$";
|
|
1336
|
+
}
|
|
1337
|
+
static isImageUrlProperty(schema, name, parentArrayName) {
|
|
1338
|
+
const propertyName = name ? name : parentArrayName;
|
|
1339
|
+
return (!!propertyName &&
|
|
1340
|
+
schema.type === "string" &&
|
|
1341
|
+
Utils.isWellKnownName(propertyName, ConstantString.WellknownImageName) &&
|
|
1342
|
+
(propertyName.toLocaleLowerCase().indexOf("url") >= 0 || schema.format === "uri"));
|
|
849
1343
|
}
|
|
850
1344
|
}
|
|
851
1345
|
|
|
852
|
-
export { ConstantString, ErrorType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
|
|
1346
|
+
export { AdaptiveCardGenerator, ConstantString, ErrorType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
|
|
853
1347
|
//# sourceMappingURL=index.esm2017.js.map
|