@microsoft/m365-spec-parser 0.1.1-alpha.78701ec6a.0 → 0.1.1-alpha.87f45d762.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 +803 -299
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +983 -409
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +807 -299
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +991 -408
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/constants.d.ts +6 -1
- package/dist/src/index.browser.d.ts +2 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/interfaces.d.ts +90 -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,36 @@ 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;
|
|
174
|
+
ConstantString.DefaultPluginId = "plugin_1";
|
|
147
175
|
|
|
148
176
|
// Copyright (c) Microsoft Corporation.
|
|
149
177
|
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 {
|
|
178
|
+
static hasNestedObjectInSchema(schema) {
|
|
179
|
+
if (schema.type === "object") {
|
|
180
|
+
for (const property in schema.properties) {
|
|
181
|
+
const nestedSchema = schema.properties[property];
|
|
182
|
+
if (nestedSchema.type === "object") {
|
|
302
183
|
return true;
|
|
303
184
|
}
|
|
304
185
|
}
|
|
305
186
|
}
|
|
306
187
|
return false;
|
|
307
188
|
}
|
|
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;
|
|
189
|
+
static containMultipleMediaTypes(bodyObject) {
|
|
190
|
+
return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
|
|
191
|
+
}
|
|
192
|
+
static isBearerTokenAuth(authScheme) {
|
|
193
|
+
return authScheme.type === "http" && authScheme.scheme === "bearer";
|
|
337
194
|
}
|
|
338
|
-
static isAPIKeyAuth(
|
|
339
|
-
return
|
|
195
|
+
static isAPIKeyAuth(authScheme) {
|
|
196
|
+
return authScheme.type === "apiKey";
|
|
340
197
|
}
|
|
341
|
-
static
|
|
342
|
-
return (
|
|
343
|
-
|
|
344
|
-
|
|
198
|
+
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
199
|
+
return !!(authScheme.type === "oauth2" &&
|
|
200
|
+
authScheme.flows &&
|
|
201
|
+
authScheme.flows.authorizationCode);
|
|
345
202
|
}
|
|
346
203
|
static getAuthArray(securities, spec) {
|
|
347
204
|
var _a;
|
|
@@ -354,7 +211,7 @@ class Utils {
|
|
|
354
211
|
for (const name in security) {
|
|
355
212
|
const auth = securitySchemas[name];
|
|
356
213
|
authArray.push({
|
|
357
|
-
|
|
214
|
+
authScheme: auth,
|
|
358
215
|
name: name,
|
|
359
216
|
});
|
|
360
217
|
}
|
|
@@ -372,18 +229,22 @@ class Utils {
|
|
|
372
229
|
static getResponseJson(operationObject) {
|
|
373
230
|
var _a, _b;
|
|
374
231
|
let json = {};
|
|
232
|
+
let multipleMediaType = false;
|
|
375
233
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
376
234
|
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
235
|
if ((_b = responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) === null || _b === void 0 ? void 0 : _b["application/json"]) {
|
|
236
|
+
multipleMediaType = false;
|
|
382
237
|
json = responseObject.content["application/json"];
|
|
383
|
-
|
|
238
|
+
if (Utils.containMultipleMediaTypes(responseObject)) {
|
|
239
|
+
multipleMediaType = true;
|
|
240
|
+
json = {};
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
384
245
|
}
|
|
385
246
|
}
|
|
386
|
-
return json;
|
|
247
|
+
return { json, multipleMediaType };
|
|
387
248
|
}
|
|
388
249
|
static convertPathToCamelCase(path) {
|
|
389
250
|
const pathSegments = path.split(/[./{]/);
|
|
@@ -403,10 +264,10 @@ class Utils {
|
|
|
403
264
|
return undefined;
|
|
404
265
|
}
|
|
405
266
|
}
|
|
406
|
-
static
|
|
267
|
+
static resolveEnv(str) {
|
|
407
268
|
const placeHolderReg = /\${{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*}}/g;
|
|
408
|
-
let matches = placeHolderReg.exec(
|
|
409
|
-
let
|
|
269
|
+
let matches = placeHolderReg.exec(str);
|
|
270
|
+
let newStr = str;
|
|
410
271
|
while (matches != null) {
|
|
411
272
|
const envVar = matches[1];
|
|
412
273
|
const envVal = process.env[envVar];
|
|
@@ -414,17 +275,17 @@ class Utils {
|
|
|
414
275
|
throw new Error(Utils.format(ConstantString.ResolveServerUrlFailed, envVar));
|
|
415
276
|
}
|
|
416
277
|
else {
|
|
417
|
-
|
|
278
|
+
newStr = newStr.replace(matches[0], envVal);
|
|
418
279
|
}
|
|
419
|
-
matches = placeHolderReg.exec(
|
|
280
|
+
matches = placeHolderReg.exec(str);
|
|
420
281
|
}
|
|
421
|
-
return
|
|
282
|
+
return newStr;
|
|
422
283
|
}
|
|
423
284
|
static checkServerUrl(servers) {
|
|
424
285
|
const errors = [];
|
|
425
286
|
let serverUrl;
|
|
426
287
|
try {
|
|
427
|
-
serverUrl = Utils.
|
|
288
|
+
serverUrl = Utils.resolveEnv(servers[0].url);
|
|
428
289
|
}
|
|
429
290
|
catch (err) {
|
|
430
291
|
errors.push({
|
|
@@ -454,7 +315,8 @@ class Utils {
|
|
|
454
315
|
}
|
|
455
316
|
return errors;
|
|
456
317
|
}
|
|
457
|
-
static validateServer(spec,
|
|
318
|
+
static validateServer(spec, options) {
|
|
319
|
+
var _a;
|
|
458
320
|
const errors = [];
|
|
459
321
|
let hasTopLevelServers = false;
|
|
460
322
|
let hasPathLevelServers = false;
|
|
@@ -475,7 +337,7 @@ class Utils {
|
|
|
475
337
|
}
|
|
476
338
|
for (const method in methods) {
|
|
477
339
|
const operationObject = methods[method];
|
|
478
|
-
if (
|
|
340
|
+
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
479
341
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
480
342
|
hasOperationLevelServers = true;
|
|
481
343
|
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
@@ -518,6 +380,7 @@ class Utils {
|
|
|
518
380
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
519
381
|
}
|
|
520
382
|
if (isRequired && schema.default === undefined) {
|
|
383
|
+
parameter.isRequired = true;
|
|
521
384
|
requiredParams.push(parameter);
|
|
522
385
|
}
|
|
523
386
|
else {
|
|
@@ -562,7 +425,7 @@ class Utils {
|
|
|
562
425
|
param.value = schema.default;
|
|
563
426
|
}
|
|
564
427
|
}
|
|
565
|
-
static parseApiInfo(operationItem,
|
|
428
|
+
static parseApiInfo(operationItem, options) {
|
|
566
429
|
var _a, _b;
|
|
567
430
|
const requiredParams = [];
|
|
568
431
|
const optionalParams = [];
|
|
@@ -576,11 +439,12 @@ class Utils {
|
|
|
576
439
|
description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
|
|
577
440
|
};
|
|
578
441
|
const schema = param.schema;
|
|
579
|
-
if (allowMultipleParameters && schema) {
|
|
442
|
+
if (options.allowMultipleParameters && schema) {
|
|
580
443
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
581
444
|
}
|
|
582
445
|
if (param.in !== "header" && param.in !== "cookie") {
|
|
583
446
|
if (param.required && (schema === null || schema === void 0 ? void 0 : schema.default) === undefined) {
|
|
447
|
+
parameter.isRequired = true;
|
|
584
448
|
requiredParams.push(parameter);
|
|
585
449
|
}
|
|
586
450
|
else {
|
|
@@ -594,19 +458,13 @@ class Utils {
|
|
|
594
458
|
const requestJson = requestBody.content["application/json"];
|
|
595
459
|
if (Object.keys(requestJson).length !== 0) {
|
|
596
460
|
const schema = requestJson.schema;
|
|
597
|
-
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
|
|
461
|
+
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
|
|
598
462
|
requiredParams.push(...requiredP);
|
|
599
463
|
optionalParams.push(...optionalP);
|
|
600
464
|
}
|
|
601
465
|
}
|
|
602
466
|
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
|
-
}
|
|
467
|
+
const parameters = [...requiredParams, ...optionalParams];
|
|
610
468
|
const command = {
|
|
611
469
|
context: ["compose"],
|
|
612
470
|
type: "query",
|
|
@@ -615,105 +473,535 @@ class Utils {
|
|
|
615
473
|
parameters: parameters,
|
|
616
474
|
description: ((_b = operationItem.description) !== null && _b !== void 0 ? _b : "").slice(0, ConstantString.CommandDescriptionMaxLens),
|
|
617
475
|
};
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
476
|
+
return command;
|
|
477
|
+
}
|
|
478
|
+
static format(str, ...args) {
|
|
479
|
+
let index = 0;
|
|
480
|
+
return str.replace(/%s/g, () => {
|
|
481
|
+
const arg = args[index++];
|
|
482
|
+
return arg !== undefined ? arg : "";
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
static getSafeRegistrationIdEnvName(authName) {
|
|
486
|
+
if (!authName) {
|
|
487
|
+
return "";
|
|
488
|
+
}
|
|
489
|
+
let safeRegistrationIdEnvName = authName.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
|
|
490
|
+
if (!safeRegistrationIdEnvName.match(/^[A-Z]/)) {
|
|
491
|
+
safeRegistrationIdEnvName = "PREFIX_" + safeRegistrationIdEnvName;
|
|
625
492
|
}
|
|
626
|
-
return
|
|
493
|
+
return safeRegistrationIdEnvName;
|
|
627
494
|
}
|
|
628
|
-
static
|
|
629
|
-
const
|
|
495
|
+
static getServerObject(spec, method, path) {
|
|
496
|
+
const pathObj = spec.paths[path];
|
|
497
|
+
const operationObject = pathObj[method];
|
|
498
|
+
const rootServer = spec.servers && spec.servers[0];
|
|
499
|
+
const methodServer = spec.paths[path].servers && spec.paths[path].servers[0];
|
|
500
|
+
const operationServer = operationObject.servers && operationObject.servers[0];
|
|
501
|
+
const serverUrl = operationServer || methodServer || rootServer;
|
|
502
|
+
return serverUrl;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// Copyright (c) Microsoft Corporation.
|
|
507
|
+
class Validator {
|
|
508
|
+
listAPIs() {
|
|
509
|
+
var _a;
|
|
510
|
+
if (this.apiMap) {
|
|
511
|
+
return this.apiMap;
|
|
512
|
+
}
|
|
513
|
+
const paths = this.spec.paths;
|
|
630
514
|
const result = {};
|
|
631
515
|
for (const path in paths) {
|
|
632
516
|
const methods = paths[path];
|
|
633
517
|
for (const method in methods) {
|
|
634
|
-
|
|
635
|
-
if (
|
|
636
|
-
const
|
|
637
|
-
result[`${method.toUpperCase()} ${path}`] =
|
|
518
|
+
const operationObject = methods[method];
|
|
519
|
+
if (((_a = this.options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
520
|
+
const validateResult = this.validateAPI(method, path);
|
|
521
|
+
result[`${method.toUpperCase()} ${path}`] = {
|
|
522
|
+
operation: operationObject,
|
|
523
|
+
isValid: validateResult.isValid,
|
|
524
|
+
reason: validateResult.reason,
|
|
525
|
+
};
|
|
638
526
|
}
|
|
639
527
|
}
|
|
640
528
|
}
|
|
529
|
+
this.apiMap = result;
|
|
641
530
|
return result;
|
|
642
531
|
}
|
|
643
|
-
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
532
|
+
validateSpecVersion() {
|
|
533
|
+
const result = { errors: [], warnings: [] };
|
|
534
|
+
if (this.spec.openapi >= "3.1.0") {
|
|
535
|
+
result.errors.push({
|
|
536
|
+
type: ErrorType.SpecVersionNotSupported,
|
|
537
|
+
content: Utils.format(ConstantString.SpecVersionNotSupported, this.spec.openapi),
|
|
538
|
+
data: this.spec.openapi,
|
|
650
539
|
});
|
|
651
540
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
541
|
+
return result;
|
|
542
|
+
}
|
|
543
|
+
validateSpecServer() {
|
|
544
|
+
const result = { errors: [], warnings: [] };
|
|
545
|
+
const serverErrors = Utils.validateServer(this.spec, this.options);
|
|
546
|
+
result.errors.push(...serverErrors);
|
|
547
|
+
return result;
|
|
548
|
+
}
|
|
549
|
+
validateSpecNoSupportAPI() {
|
|
550
|
+
const result = { errors: [], warnings: [] };
|
|
551
|
+
const apiMap = this.listAPIs();
|
|
552
|
+
const validAPIs = Object.entries(apiMap).filter(([, value]) => value.isValid);
|
|
553
|
+
if (validAPIs.length === 0) {
|
|
554
|
+
const data = [];
|
|
555
|
+
for (const key in apiMap) {
|
|
556
|
+
const { reason } = apiMap[key];
|
|
557
|
+
const apiInvalidReason = { api: key, reason: reason };
|
|
558
|
+
data.push(apiInvalidReason);
|
|
559
|
+
}
|
|
560
|
+
result.errors.push({
|
|
669
561
|
type: ErrorType.NoSupportedApi,
|
|
670
562
|
content: ConstantString.NoSupportedApi,
|
|
563
|
+
data,
|
|
671
564
|
});
|
|
672
565
|
}
|
|
566
|
+
return result;
|
|
567
|
+
}
|
|
568
|
+
validateSpecOperationId() {
|
|
569
|
+
const result = { errors: [], warnings: [] };
|
|
570
|
+
const apiMap = this.listAPIs();
|
|
673
571
|
// OperationId missing
|
|
674
572
|
const apisMissingOperationId = [];
|
|
675
573
|
for (const key in apiMap) {
|
|
676
|
-
const
|
|
677
|
-
if (!
|
|
574
|
+
const { operation } = apiMap[key];
|
|
575
|
+
if (!operation.operationId) {
|
|
678
576
|
apisMissingOperationId.push(key);
|
|
679
577
|
}
|
|
680
578
|
}
|
|
681
579
|
if (apisMissingOperationId.length > 0) {
|
|
682
|
-
warnings.push({
|
|
580
|
+
result.warnings.push({
|
|
683
581
|
type: WarningType.OperationIdMissing,
|
|
684
582
|
content: Utils.format(ConstantString.MissingOperationId, apisMissingOperationId.join(", ")),
|
|
685
583
|
data: apisMissingOperationId,
|
|
686
584
|
});
|
|
687
585
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
586
|
+
return result;
|
|
587
|
+
}
|
|
588
|
+
validateMethodAndPath(method, path) {
|
|
589
|
+
const result = { isValid: true, reason: [] };
|
|
590
|
+
if (this.options.allowMethods && !this.options.allowMethods.includes(method)) {
|
|
591
|
+
result.isValid = false;
|
|
592
|
+
result.reason.push(ErrorType.MethodNotAllowed);
|
|
593
|
+
return result;
|
|
594
|
+
}
|
|
595
|
+
const pathObj = this.spec.paths[path];
|
|
596
|
+
if (!pathObj || !pathObj[method]) {
|
|
597
|
+
result.isValid = false;
|
|
598
|
+
result.reason.push(ErrorType.UrlPathNotExist);
|
|
599
|
+
return result;
|
|
600
|
+
}
|
|
601
|
+
return result;
|
|
602
|
+
}
|
|
603
|
+
validateResponse(method, path) {
|
|
604
|
+
const result = { isValid: true, reason: [] };
|
|
605
|
+
const operationObject = this.spec.paths[path][method];
|
|
606
|
+
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
607
|
+
// only support response body only contains “application/json” content type
|
|
608
|
+
if (multipleMediaType) {
|
|
609
|
+
result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
|
|
610
|
+
}
|
|
611
|
+
else if (Object.keys(json).length === 0) {
|
|
612
|
+
// response body should not be empty
|
|
613
|
+
result.reason.push(ErrorType.ResponseJsonIsEmpty);
|
|
614
|
+
}
|
|
615
|
+
return result;
|
|
616
|
+
}
|
|
617
|
+
validateServer(method, path) {
|
|
618
|
+
const result = { isValid: true, reason: [] };
|
|
619
|
+
const serverObj = Utils.getServerObject(this.spec, method, path);
|
|
620
|
+
if (!serverObj) {
|
|
621
|
+
// should contain server URL
|
|
622
|
+
result.reason.push(ErrorType.NoServerInformation);
|
|
623
|
+
}
|
|
624
|
+
else {
|
|
625
|
+
// server url should be absolute url with https protocol
|
|
626
|
+
const serverValidateResult = Utils.checkServerUrl([serverObj]);
|
|
627
|
+
result.reason.push(...serverValidateResult.map((item) => item.type));
|
|
628
|
+
}
|
|
629
|
+
return result;
|
|
630
|
+
}
|
|
631
|
+
validateAuth(method, path) {
|
|
632
|
+
const pathObj = this.spec.paths[path];
|
|
633
|
+
const operationObject = pathObj[method];
|
|
634
|
+
const securities = operationObject.security;
|
|
635
|
+
const authSchemeArray = Utils.getAuthArray(securities, this.spec);
|
|
636
|
+
if (authSchemeArray.length === 0) {
|
|
637
|
+
return { isValid: true, reason: [] };
|
|
638
|
+
}
|
|
639
|
+
if (this.options.allowAPIKeyAuth ||
|
|
640
|
+
this.options.allowOauth2 ||
|
|
641
|
+
this.options.allowBearerTokenAuth) {
|
|
642
|
+
// Currently we don't support multiple auth in one operation
|
|
643
|
+
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
644
|
+
return {
|
|
645
|
+
isValid: false,
|
|
646
|
+
reason: [ErrorType.MultipleAuthNotSupported],
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
for (const auths of authSchemeArray) {
|
|
650
|
+
if (auths.length === 1) {
|
|
651
|
+
if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
652
|
+
(this.options.allowOauth2 && Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme)) ||
|
|
653
|
+
(this.options.allowBearerTokenAuth && Utils.isBearerTokenAuth(auths[0].authScheme))) {
|
|
654
|
+
return { isValid: true, reason: [] };
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
|
|
660
|
+
}
|
|
661
|
+
checkPostBodySchema(schema, isRequired = false) {
|
|
662
|
+
var _a;
|
|
663
|
+
const paramResult = {
|
|
664
|
+
requiredNum: 0,
|
|
665
|
+
optionalNum: 0,
|
|
666
|
+
isValid: true,
|
|
667
|
+
reason: [],
|
|
668
|
+
};
|
|
669
|
+
if (Object.keys(schema).length === 0) {
|
|
670
|
+
return paramResult;
|
|
671
|
+
}
|
|
672
|
+
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
673
|
+
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
674
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
675
|
+
paramResult.isValid = false;
|
|
676
|
+
paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
|
|
677
|
+
return paramResult;
|
|
678
|
+
}
|
|
679
|
+
if (schema.type === "string" ||
|
|
680
|
+
schema.type === "integer" ||
|
|
681
|
+
schema.type === "boolean" ||
|
|
682
|
+
schema.type === "number") {
|
|
683
|
+
if (isRequiredWithoutDefault) {
|
|
684
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
else if (schema.type === "object") {
|
|
691
|
+
const { properties } = schema;
|
|
692
|
+
for (const property in properties) {
|
|
693
|
+
let isRequired = false;
|
|
694
|
+
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
695
|
+
isRequired = true;
|
|
696
|
+
}
|
|
697
|
+
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
698
|
+
paramResult.requiredNum += result.requiredNum;
|
|
699
|
+
paramResult.optionalNum += result.optionalNum;
|
|
700
|
+
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
701
|
+
paramResult.reason.push(...result.reason);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
else {
|
|
705
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
706
|
+
paramResult.isValid = false;
|
|
707
|
+
paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
return paramResult;
|
|
711
|
+
}
|
|
712
|
+
checkParamSchema(paramObject) {
|
|
713
|
+
const paramResult = {
|
|
714
|
+
requiredNum: 0,
|
|
715
|
+
optionalNum: 0,
|
|
716
|
+
isValid: true,
|
|
717
|
+
reason: [],
|
|
718
|
+
};
|
|
719
|
+
if (!paramObject) {
|
|
720
|
+
return paramResult;
|
|
721
|
+
}
|
|
722
|
+
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
723
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
724
|
+
const param = paramObject[i];
|
|
725
|
+
const schema = param.schema;
|
|
726
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
727
|
+
paramResult.isValid = false;
|
|
728
|
+
paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
|
|
729
|
+
continue;
|
|
730
|
+
}
|
|
731
|
+
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
732
|
+
if (isCopilot) {
|
|
733
|
+
if (isRequiredWithoutDefault) {
|
|
734
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
738
|
+
}
|
|
739
|
+
continue;
|
|
740
|
+
}
|
|
741
|
+
if (param.in === "header" || param.in === "cookie") {
|
|
742
|
+
if (isRequiredWithoutDefault) {
|
|
743
|
+
paramResult.isValid = false;
|
|
744
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
745
|
+
}
|
|
746
|
+
continue;
|
|
747
|
+
}
|
|
748
|
+
if (schema.type !== "boolean" &&
|
|
749
|
+
schema.type !== "string" &&
|
|
750
|
+
schema.type !== "number" &&
|
|
751
|
+
schema.type !== "integer") {
|
|
752
|
+
if (isRequiredWithoutDefault) {
|
|
753
|
+
paramResult.isValid = false;
|
|
754
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
755
|
+
}
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
758
|
+
if (param.in === "query" || param.in === "path") {
|
|
759
|
+
if (isRequiredWithoutDefault) {
|
|
760
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
761
|
+
}
|
|
762
|
+
else {
|
|
763
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
return paramResult;
|
|
768
|
+
}
|
|
769
|
+
hasNestedObjectInSchema(schema) {
|
|
770
|
+
if (schema.type === "object") {
|
|
771
|
+
for (const property in schema.properties) {
|
|
772
|
+
const nestedSchema = schema.properties[property];
|
|
773
|
+
if (nestedSchema.type === "object") {
|
|
774
|
+
return true;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// Copyright (c) Microsoft Corporation.
|
|
783
|
+
class CopilotValidator extends Validator {
|
|
784
|
+
constructor(spec, options) {
|
|
785
|
+
super();
|
|
786
|
+
this.projectType = ProjectType.Copilot;
|
|
787
|
+
this.options = options;
|
|
788
|
+
this.spec = spec;
|
|
789
|
+
}
|
|
790
|
+
validateSpec() {
|
|
791
|
+
const result = { errors: [], warnings: [] };
|
|
792
|
+
// validate spec version
|
|
793
|
+
let validationResult = this.validateSpecVersion();
|
|
794
|
+
result.errors.push(...validationResult.errors);
|
|
795
|
+
// validate spec server
|
|
796
|
+
validationResult = this.validateSpecServer();
|
|
797
|
+
result.errors.push(...validationResult.errors);
|
|
798
|
+
// validate no supported API
|
|
799
|
+
validationResult = this.validateSpecNoSupportAPI();
|
|
800
|
+
result.errors.push(...validationResult.errors);
|
|
801
|
+
// validate operationId missing
|
|
802
|
+
validationResult = this.validateSpecOperationId();
|
|
803
|
+
result.warnings.push(...validationResult.warnings);
|
|
804
|
+
return result;
|
|
805
|
+
}
|
|
806
|
+
validateAPI(method, path) {
|
|
807
|
+
const result = { isValid: true, reason: [] };
|
|
808
|
+
method = method.toLocaleLowerCase();
|
|
809
|
+
// validate method and path
|
|
810
|
+
const methodAndPathResult = this.validateMethodAndPath(method, path);
|
|
811
|
+
if (!methodAndPathResult.isValid) {
|
|
812
|
+
return methodAndPathResult;
|
|
813
|
+
}
|
|
814
|
+
const operationObject = this.spec.paths[path][method];
|
|
815
|
+
// validate auth
|
|
816
|
+
const authCheckResult = this.validateAuth(method, path);
|
|
817
|
+
result.reason.push(...authCheckResult.reason);
|
|
818
|
+
// validate operationId
|
|
819
|
+
if (!this.options.allowMissingId && !operationObject.operationId) {
|
|
820
|
+
result.reason.push(ErrorType.MissingOperationId);
|
|
821
|
+
}
|
|
822
|
+
// validate server
|
|
823
|
+
const validateServerResult = this.validateServer(method, path);
|
|
824
|
+
result.reason.push(...validateServerResult.reason);
|
|
825
|
+
// validate response
|
|
826
|
+
const validateResponseResult = this.validateResponse(method, path);
|
|
827
|
+
result.reason.push(...validateResponseResult.reason);
|
|
828
|
+
// validate requestBody
|
|
829
|
+
const requestBody = operationObject.requestBody;
|
|
830
|
+
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
831
|
+
if (Utils.containMultipleMediaTypes(requestBody)) {
|
|
832
|
+
result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
|
|
691
833
|
}
|
|
692
|
-
|
|
693
|
-
|
|
834
|
+
if (requestJsonBody) {
|
|
835
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
836
|
+
if (requestBodySchema.type !== "object") {
|
|
837
|
+
result.reason.push(ErrorType.PostBodySchemaIsNotJson);
|
|
838
|
+
}
|
|
839
|
+
const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
|
|
840
|
+
result.reason.push(...requestBodyParamResult.reason);
|
|
841
|
+
}
|
|
842
|
+
// validate parameters
|
|
843
|
+
const paramObject = operationObject.parameters;
|
|
844
|
+
const paramResult = this.checkParamSchema(paramObject);
|
|
845
|
+
result.reason.push(...paramResult.reason);
|
|
846
|
+
if (result.reason.length > 0) {
|
|
847
|
+
result.isValid = false;
|
|
848
|
+
}
|
|
849
|
+
return result;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// Copyright (c) Microsoft Corporation.
|
|
854
|
+
class SMEValidator extends Validator {
|
|
855
|
+
constructor(spec, options) {
|
|
856
|
+
super();
|
|
857
|
+
this.projectType = ProjectType.SME;
|
|
858
|
+
this.options = options;
|
|
859
|
+
this.spec = spec;
|
|
860
|
+
}
|
|
861
|
+
validateSpec() {
|
|
862
|
+
const result = { errors: [], warnings: [] };
|
|
863
|
+
// validate spec version
|
|
864
|
+
let validationResult = this.validateSpecVersion();
|
|
865
|
+
result.errors.push(...validationResult.errors);
|
|
866
|
+
// validate spec server
|
|
867
|
+
validationResult = this.validateSpecServer();
|
|
868
|
+
result.errors.push(...validationResult.errors);
|
|
869
|
+
// validate no supported API
|
|
870
|
+
validationResult = this.validateSpecNoSupportAPI();
|
|
871
|
+
result.errors.push(...validationResult.errors);
|
|
872
|
+
// validate operationId missing
|
|
873
|
+
if (this.options.allowMissingId) {
|
|
874
|
+
validationResult = this.validateSpecOperationId();
|
|
875
|
+
result.warnings.push(...validationResult.warnings);
|
|
876
|
+
}
|
|
877
|
+
return result;
|
|
878
|
+
}
|
|
879
|
+
validateAPI(method, path) {
|
|
880
|
+
const result = { isValid: true, reason: [] };
|
|
881
|
+
method = method.toLocaleLowerCase();
|
|
882
|
+
// validate method and path
|
|
883
|
+
const methodAndPathResult = this.validateMethodAndPath(method, path);
|
|
884
|
+
if (!methodAndPathResult.isValid) {
|
|
885
|
+
return methodAndPathResult;
|
|
694
886
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
887
|
+
const operationObject = this.spec.paths[path][method];
|
|
888
|
+
// validate auth
|
|
889
|
+
const authCheckResult = this.validateAuth(method, path);
|
|
890
|
+
result.reason.push(...authCheckResult.reason);
|
|
891
|
+
// validate operationId
|
|
892
|
+
if (!this.options.allowMissingId && !operationObject.operationId) {
|
|
893
|
+
result.reason.push(ErrorType.MissingOperationId);
|
|
894
|
+
}
|
|
895
|
+
// validate server
|
|
896
|
+
const validateServerResult = this.validateServer(method, path);
|
|
897
|
+
result.reason.push(...validateServerResult.reason);
|
|
898
|
+
// validate response
|
|
899
|
+
const validateResponseResult = this.validateResponse(method, path);
|
|
900
|
+
result.reason.push(...validateResponseResult.reason);
|
|
901
|
+
let postBodyResult = {
|
|
902
|
+
requiredNum: 0,
|
|
903
|
+
optionalNum: 0,
|
|
904
|
+
isValid: true,
|
|
905
|
+
reason: [],
|
|
699
906
|
};
|
|
907
|
+
// validate requestBody
|
|
908
|
+
const requestBody = operationObject.requestBody;
|
|
909
|
+
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
910
|
+
if (Utils.containMultipleMediaTypes(requestBody)) {
|
|
911
|
+
result.reason.push(ErrorType.PostBodyContainMultipleMediaTypes);
|
|
912
|
+
}
|
|
913
|
+
if (requestJsonBody) {
|
|
914
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
915
|
+
postBodyResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
|
|
916
|
+
result.reason.push(...postBodyResult.reason);
|
|
917
|
+
}
|
|
918
|
+
// validate parameters
|
|
919
|
+
const paramObject = operationObject.parameters;
|
|
920
|
+
const paramResult = this.checkParamSchema(paramObject);
|
|
921
|
+
result.reason.push(...paramResult.reason);
|
|
922
|
+
// validate total parameters count
|
|
923
|
+
if (paramResult.isValid && postBodyResult.isValid) {
|
|
924
|
+
const paramCountResult = this.validateParamCount(postBodyResult, paramResult);
|
|
925
|
+
result.reason.push(...paramCountResult.reason);
|
|
926
|
+
}
|
|
927
|
+
if (result.reason.length > 0) {
|
|
928
|
+
result.isValid = false;
|
|
929
|
+
}
|
|
930
|
+
return result;
|
|
700
931
|
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
932
|
+
validateParamCount(postBodyResult, paramResult) {
|
|
933
|
+
const result = { isValid: true, reason: [] };
|
|
934
|
+
const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
|
|
935
|
+
const totalParams = totalRequiredParams + postBodyResult.optionalNum + paramResult.optionalNum;
|
|
936
|
+
if (totalRequiredParams > 1) {
|
|
937
|
+
if (!this.options.allowMultipleParameters ||
|
|
938
|
+
totalRequiredParams > SMEValidator.SMERequiredParamsMaxNum) {
|
|
939
|
+
result.reason.push(ErrorType.ExceededRequiredParamsLimit);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
else if (totalParams === 0) {
|
|
943
|
+
result.reason.push(ErrorType.NoParameter);
|
|
944
|
+
}
|
|
945
|
+
return result;
|
|
707
946
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
947
|
+
}
|
|
948
|
+
SMEValidator.SMERequiredParamsMaxNum = 5;
|
|
949
|
+
|
|
950
|
+
// Copyright (c) Microsoft Corporation.
|
|
951
|
+
class TeamsAIValidator extends Validator {
|
|
952
|
+
constructor(spec, options) {
|
|
953
|
+
super();
|
|
954
|
+
this.projectType = ProjectType.TeamsAi;
|
|
955
|
+
this.options = options;
|
|
956
|
+
this.spec = spec;
|
|
957
|
+
}
|
|
958
|
+
validateSpec() {
|
|
959
|
+
const result = { errors: [], warnings: [] };
|
|
960
|
+
// validate spec server
|
|
961
|
+
let validationResult = this.validateSpecServer();
|
|
962
|
+
result.errors.push(...validationResult.errors);
|
|
963
|
+
// validate no supported API
|
|
964
|
+
validationResult = this.validateSpecNoSupportAPI();
|
|
965
|
+
result.errors.push(...validationResult.errors);
|
|
966
|
+
return result;
|
|
967
|
+
}
|
|
968
|
+
validateAPI(method, path) {
|
|
969
|
+
const result = { isValid: true, reason: [] };
|
|
970
|
+
method = method.toLocaleLowerCase();
|
|
971
|
+
// validate method and path
|
|
972
|
+
const methodAndPathResult = this.validateMethodAndPath(method, path);
|
|
973
|
+
if (!methodAndPathResult.isValid) {
|
|
974
|
+
return methodAndPathResult;
|
|
711
975
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
976
|
+
const operationObject = this.spec.paths[path][method];
|
|
977
|
+
// validate operationId
|
|
978
|
+
if (!this.options.allowMissingId && !operationObject.operationId) {
|
|
979
|
+
result.reason.push(ErrorType.MissingOperationId);
|
|
980
|
+
}
|
|
981
|
+
// validate server
|
|
982
|
+
const validateServerResult = this.validateServer(method, path);
|
|
983
|
+
result.reason.push(...validateServerResult.reason);
|
|
984
|
+
if (result.reason.length > 0) {
|
|
985
|
+
result.isValid = false;
|
|
986
|
+
}
|
|
987
|
+
return result;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
class ValidatorFactory {
|
|
992
|
+
static create(spec, options) {
|
|
993
|
+
var _a;
|
|
994
|
+
const type = (_a = options.projectType) !== null && _a !== void 0 ? _a : ProjectType.SME;
|
|
995
|
+
switch (type) {
|
|
996
|
+
case ProjectType.SME:
|
|
997
|
+
return new SMEValidator(spec, options);
|
|
998
|
+
case ProjectType.Copilot:
|
|
999
|
+
return new CopilotValidator(spec, options);
|
|
1000
|
+
case ProjectType.TeamsAi:
|
|
1001
|
+
return new TeamsAIValidator(spec, options);
|
|
1002
|
+
default:
|
|
1003
|
+
throw new Error(`Invalid project type: ${type}`);
|
|
715
1004
|
}
|
|
716
|
-
return safeRegistrationIdEnvName;
|
|
717
1005
|
}
|
|
718
1006
|
}
|
|
719
1007
|
|
|
@@ -733,7 +1021,10 @@ class SpecParser {
|
|
|
733
1021
|
allowSwagger: false,
|
|
734
1022
|
allowAPIKeyAuth: false,
|
|
735
1023
|
allowMultipleParameters: false,
|
|
1024
|
+
allowBearerTokenAuth: false,
|
|
736
1025
|
allowOauth2: false,
|
|
1026
|
+
allowMethods: ["get", "post"],
|
|
1027
|
+
projectType: ProjectType.SME,
|
|
737
1028
|
};
|
|
738
1029
|
this.pathOrSpec = pathOrDoc;
|
|
739
1030
|
this.parser = new SwaggerParser();
|
|
@@ -748,11 +1039,7 @@ class SpecParser {
|
|
|
748
1039
|
try {
|
|
749
1040
|
try {
|
|
750
1041
|
await this.loadSpec();
|
|
751
|
-
await this.parser.validate(this.spec
|
|
752
|
-
validate: {
|
|
753
|
-
schema: false,
|
|
754
|
-
},
|
|
755
|
-
});
|
|
1042
|
+
await this.parser.validate(this.spec);
|
|
756
1043
|
}
|
|
757
1044
|
catch (e) {
|
|
758
1045
|
return {
|
|
@@ -761,16 +1048,46 @@ class SpecParser {
|
|
|
761
1048
|
errors: [{ type: ErrorType.SpecNotValid, content: e.toString() }],
|
|
762
1049
|
};
|
|
763
1050
|
}
|
|
1051
|
+
const errors = [];
|
|
1052
|
+
const warnings = [];
|
|
764
1053
|
if (!this.options.allowSwagger && this.isSwaggerFile) {
|
|
765
1054
|
return {
|
|
766
1055
|
status: ValidationStatus.Error,
|
|
767
1056
|
warnings: [],
|
|
768
1057
|
errors: [
|
|
769
|
-
{
|
|
1058
|
+
{
|
|
1059
|
+
type: ErrorType.SwaggerNotSupported,
|
|
1060
|
+
content: ConstantString.SwaggerNotSupported,
|
|
1061
|
+
},
|
|
770
1062
|
],
|
|
771
1063
|
};
|
|
772
1064
|
}
|
|
773
|
-
|
|
1065
|
+
// Remote reference not supported
|
|
1066
|
+
const refPaths = this.parser.$refs.paths();
|
|
1067
|
+
// refPaths [0] is the current spec file path
|
|
1068
|
+
if (refPaths.length > 1) {
|
|
1069
|
+
errors.push({
|
|
1070
|
+
type: ErrorType.RemoteRefNotSupported,
|
|
1071
|
+
content: Utils.format(ConstantString.RemoteRefNotSupported, refPaths.join(", ")),
|
|
1072
|
+
data: refPaths,
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
const validator = this.getValidator(this.spec);
|
|
1076
|
+
const validationResult = validator.validateSpec();
|
|
1077
|
+
warnings.push(...validationResult.warnings);
|
|
1078
|
+
errors.push(...validationResult.errors);
|
|
1079
|
+
let status = ValidationStatus.Valid;
|
|
1080
|
+
if (warnings.length > 0 && errors.length === 0) {
|
|
1081
|
+
status = ValidationStatus.Warning;
|
|
1082
|
+
}
|
|
1083
|
+
else if (errors.length > 0) {
|
|
1084
|
+
status = ValidationStatus.Error;
|
|
1085
|
+
}
|
|
1086
|
+
return {
|
|
1087
|
+
status: status,
|
|
1088
|
+
warnings: warnings,
|
|
1089
|
+
errors: errors,
|
|
1090
|
+
};
|
|
774
1091
|
}
|
|
775
1092
|
catch (err) {
|
|
776
1093
|
throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
|
|
@@ -779,17 +1096,20 @@ class SpecParser {
|
|
|
779
1096
|
async listSupportedAPIInfo() {
|
|
780
1097
|
try {
|
|
781
1098
|
await this.loadSpec();
|
|
782
|
-
const apiMap = this.
|
|
1099
|
+
const apiMap = this.getAPIs(this.spec);
|
|
783
1100
|
const apiInfos = [];
|
|
784
1101
|
for (const key in apiMap) {
|
|
785
|
-
const
|
|
1102
|
+
const { operation, isValid } = apiMap[key];
|
|
1103
|
+
if (!isValid) {
|
|
1104
|
+
continue;
|
|
1105
|
+
}
|
|
786
1106
|
const [method, path] = key.split(" ");
|
|
787
|
-
const operationId =
|
|
1107
|
+
const operationId = operation.operationId;
|
|
788
1108
|
// In Browser environment, this api is by default not support api without operationId
|
|
789
1109
|
if (!operationId) {
|
|
790
1110
|
continue;
|
|
791
1111
|
}
|
|
792
|
-
const
|
|
1112
|
+
const command = Utils.parseApiInfo(operation, this.options);
|
|
793
1113
|
const apiInfo = {
|
|
794
1114
|
method: method,
|
|
795
1115
|
path: path,
|
|
@@ -798,9 +1118,6 @@ class SpecParser {
|
|
|
798
1118
|
parameters: command.parameters,
|
|
799
1119
|
description: command.description,
|
|
800
1120
|
};
|
|
801
|
-
if (warning) {
|
|
802
|
-
apiInfo.warning = warning;
|
|
803
|
-
}
|
|
804
1121
|
apiInfos.push(apiInfo);
|
|
805
1122
|
}
|
|
806
1123
|
return apiInfos;
|
|
@@ -818,12 +1135,32 @@ class SpecParser {
|
|
|
818
1135
|
async list() {
|
|
819
1136
|
throw new Error("Method not implemented.");
|
|
820
1137
|
}
|
|
1138
|
+
/**
|
|
1139
|
+
* Generate specs according to the filters.
|
|
1140
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
1141
|
+
*/
|
|
1142
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
1143
|
+
async getFilteredSpecs(filter, signal) {
|
|
1144
|
+
throw new Error("Method not implemented.");
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
1148
|
+
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
1149
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
1150
|
+
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
1151
|
+
* @param pluginFilePath File path of the api plugin file to generate.
|
|
1152
|
+
*/
|
|
1153
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
1154
|
+
async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
|
|
1155
|
+
throw new Error("Method not implemented.");
|
|
1156
|
+
}
|
|
821
1157
|
/**
|
|
822
1158
|
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
823
1159
|
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
824
1160
|
* @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
1161
|
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
826
1162
|
* @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
|
|
1163
|
+
* @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
|
|
827
1164
|
*/
|
|
828
1165
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
829
1166
|
async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
|
|
@@ -839,15 +1176,182 @@ class SpecParser {
|
|
|
839
1176
|
this.spec = (await this.parser.dereference(clonedUnResolveSpec));
|
|
840
1177
|
}
|
|
841
1178
|
}
|
|
842
|
-
|
|
1179
|
+
getAPIs(spec) {
|
|
843
1180
|
if (this.apiMap !== undefined) {
|
|
844
1181
|
return this.apiMap;
|
|
845
1182
|
}
|
|
846
|
-
const
|
|
847
|
-
|
|
848
|
-
|
|
1183
|
+
const validator = this.getValidator(spec);
|
|
1184
|
+
const apiMap = validator.listAPIs();
|
|
1185
|
+
this.apiMap = apiMap;
|
|
1186
|
+
return apiMap;
|
|
1187
|
+
}
|
|
1188
|
+
getValidator(spec) {
|
|
1189
|
+
if (this.validator) {
|
|
1190
|
+
return this.validator;
|
|
1191
|
+
}
|
|
1192
|
+
const validator = ValidatorFactory.create(spec, this.options);
|
|
1193
|
+
this.validator = validator;
|
|
1194
|
+
return validator;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
// Copyright (c) Microsoft Corporation.
|
|
1199
|
+
class AdaptiveCardGenerator {
|
|
1200
|
+
static generateAdaptiveCard(operationItem) {
|
|
1201
|
+
try {
|
|
1202
|
+
const { json } = Utils.getResponseJson(operationItem);
|
|
1203
|
+
let cardBody = [];
|
|
1204
|
+
let schema = json.schema;
|
|
1205
|
+
let jsonPath = "$";
|
|
1206
|
+
if (schema && Object.keys(schema).length > 0) {
|
|
1207
|
+
jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
|
|
1208
|
+
if (jsonPath !== "$") {
|
|
1209
|
+
schema = schema.properties[jsonPath];
|
|
1210
|
+
}
|
|
1211
|
+
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
|
|
1212
|
+
}
|
|
1213
|
+
// if no schema, try to use example value
|
|
1214
|
+
if (cardBody.length === 0 && (json.examples || json.example)) {
|
|
1215
|
+
cardBody = [
|
|
1216
|
+
{
|
|
1217
|
+
type: ConstantString.TextBlockType,
|
|
1218
|
+
text: "${jsonStringify($root)}",
|
|
1219
|
+
wrap: true,
|
|
1220
|
+
},
|
|
1221
|
+
];
|
|
1222
|
+
}
|
|
1223
|
+
// if no example value, use default success response
|
|
1224
|
+
if (cardBody.length === 0) {
|
|
1225
|
+
cardBody = [
|
|
1226
|
+
{
|
|
1227
|
+
type: ConstantString.TextBlockType,
|
|
1228
|
+
text: "success",
|
|
1229
|
+
wrap: true,
|
|
1230
|
+
},
|
|
1231
|
+
];
|
|
1232
|
+
}
|
|
1233
|
+
const fullCard = {
|
|
1234
|
+
type: ConstantString.AdaptiveCardType,
|
|
1235
|
+
$schema: ConstantString.AdaptiveCardSchema,
|
|
1236
|
+
version: ConstantString.AdaptiveCardVersion,
|
|
1237
|
+
body: cardBody,
|
|
1238
|
+
};
|
|
1239
|
+
return [fullCard, jsonPath];
|
|
1240
|
+
}
|
|
1241
|
+
catch (err) {
|
|
1242
|
+
throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
static generateCardFromResponse(schema, name, parentArrayName = "") {
|
|
1246
|
+
if (schema.type === "array") {
|
|
1247
|
+
// schema.items can be arbitrary object: schema { type: array, items: {} }
|
|
1248
|
+
if (Object.keys(schema.items).length === 0) {
|
|
1249
|
+
return [
|
|
1250
|
+
{
|
|
1251
|
+
type: ConstantString.TextBlockType,
|
|
1252
|
+
text: name ? `${name}: \${jsonStringify(${name})}` : "result: ${jsonStringify($root)}",
|
|
1253
|
+
wrap: true,
|
|
1254
|
+
},
|
|
1255
|
+
];
|
|
1256
|
+
}
|
|
1257
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
|
|
1258
|
+
const template = {
|
|
1259
|
+
type: ConstantString.ContainerType,
|
|
1260
|
+
$data: name ? `\${${name}}` : "${$root}",
|
|
1261
|
+
items: Array(),
|
|
1262
|
+
};
|
|
1263
|
+
template.items.push(...obj);
|
|
1264
|
+
return [template];
|
|
1265
|
+
}
|
|
1266
|
+
// some schema may not contain type but contain properties
|
|
1267
|
+
if (schema.type === "object" || (!schema.type && schema.properties)) {
|
|
1268
|
+
const { properties } = schema;
|
|
1269
|
+
const result = [];
|
|
1270
|
+
for (const property in properties) {
|
|
1271
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
|
|
1272
|
+
result.push(...obj);
|
|
1273
|
+
}
|
|
1274
|
+
if (schema.additionalProperties) {
|
|
1275
|
+
// TODO: better ways to handler warnings.
|
|
1276
|
+
console.warn(ConstantString.AdditionalPropertiesNotSupported);
|
|
1277
|
+
}
|
|
1278
|
+
return result;
|
|
1279
|
+
}
|
|
1280
|
+
if (schema.type === "string" ||
|
|
1281
|
+
schema.type === "integer" ||
|
|
1282
|
+
schema.type === "boolean" ||
|
|
1283
|
+
schema.type === "number") {
|
|
1284
|
+
if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
|
|
1285
|
+
// string in root: "ddd"
|
|
1286
|
+
let text = "result: ${$root}";
|
|
1287
|
+
if (name) {
|
|
1288
|
+
// object { id: "1" }
|
|
1289
|
+
text = `${name}: \${if(${name}, ${name}, 'N/A')}`;
|
|
1290
|
+
if (parentArrayName) {
|
|
1291
|
+
// object types inside array: { tags: ["id": 1, "name": "name"] }
|
|
1292
|
+
text = `${parentArrayName}.${text}`;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
else if (parentArrayName) {
|
|
1296
|
+
// string array: photoUrls: ["1", "2"]
|
|
1297
|
+
text = `${parentArrayName}: ` + "${$data}";
|
|
1298
|
+
}
|
|
1299
|
+
return [
|
|
1300
|
+
{
|
|
1301
|
+
type: ConstantString.TextBlockType,
|
|
1302
|
+
text,
|
|
1303
|
+
wrap: true,
|
|
1304
|
+
},
|
|
1305
|
+
];
|
|
1306
|
+
}
|
|
1307
|
+
else {
|
|
1308
|
+
if (name) {
|
|
1309
|
+
return [
|
|
1310
|
+
{
|
|
1311
|
+
type: "Image",
|
|
1312
|
+
url: `\${${name}}`,
|
|
1313
|
+
$when: `\${${name} != null}`,
|
|
1314
|
+
},
|
|
1315
|
+
];
|
|
1316
|
+
}
|
|
1317
|
+
else {
|
|
1318
|
+
return [
|
|
1319
|
+
{
|
|
1320
|
+
type: "Image",
|
|
1321
|
+
url: "${$data}",
|
|
1322
|
+
$when: "${$data != null}",
|
|
1323
|
+
},
|
|
1324
|
+
];
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
|
|
1329
|
+
throw new Error(Utils.format(ConstantString.SchemaNotSupported, JSON.stringify(schema)));
|
|
1330
|
+
}
|
|
1331
|
+
throw new Error(Utils.format(ConstantString.UnknownSchema, JSON.stringify(schema)));
|
|
1332
|
+
}
|
|
1333
|
+
// Find the first array property in the response schema object with the well-known name
|
|
1334
|
+
static getResponseJsonPathFromSchema(schema) {
|
|
1335
|
+
if (schema.type === "object" || (!schema.type && schema.properties)) {
|
|
1336
|
+
const { properties } = schema;
|
|
1337
|
+
for (const property in properties) {
|
|
1338
|
+
const schema = properties[property];
|
|
1339
|
+
if (schema.type === "array" &&
|
|
1340
|
+
Utils.isWellKnownName(property, ConstantString.WellknownResultNames)) {
|
|
1341
|
+
return property;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
return "$";
|
|
1346
|
+
}
|
|
1347
|
+
static isImageUrlProperty(schema, name, parentArrayName) {
|
|
1348
|
+
const propertyName = name ? name : parentArrayName;
|
|
1349
|
+
return (!!propertyName &&
|
|
1350
|
+
schema.type === "string" &&
|
|
1351
|
+
Utils.isWellKnownName(propertyName, ConstantString.WellknownImageName) &&
|
|
1352
|
+
(propertyName.toLocaleLowerCase().indexOf("url") >= 0 || schema.format === "uri"));
|
|
849
1353
|
}
|
|
850
1354
|
}
|
|
851
1355
|
|
|
852
|
-
export { ConstantString, ErrorType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
|
|
1356
|
+
export { AdaptiveCardGenerator, ConstantString, ErrorType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
|
|
853
1357
|
//# sourceMappingURL=index.esm2017.js.map
|