@microsoft/m365-spec-parser 0.2.3 → 0.2.4-alpha.24cc1dfce.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 +344 -253
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +481 -332
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +344 -253
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +484 -333
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/adaptiveCardGenerator.d.ts +5 -3
- package/dist/src/constants.d.ts +5 -4
- package/dist/src/interfaces.d.ts +12 -3
- package/dist/src/jsonDataGenerator.d.ts +6 -0
- package/dist/src/manifestUpdater.d.ts +3 -3
- package/dist/src/specParser.d.ts +2 -0
- package/dist/src/utils.d.ts +7 -4
- package/package.json +4 -4
package/dist/index.esm2017.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import fs from 'fs-extra';
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { ManifestUtil } from '@microsoft/teams-manifest';
|
|
7
7
|
import { createHash } from 'crypto';
|
|
8
|
+
import { $RefParser } from '@apidevtools/json-schema-ref-parser';
|
|
8
9
|
|
|
9
10
|
// Copyright (c) Microsoft Corporation.
|
|
10
11
|
/**
|
|
@@ -38,11 +39,8 @@ var ErrorType;
|
|
|
38
39
|
ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
|
|
39
40
|
ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
|
|
40
41
|
ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
|
|
41
|
-
ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
|
|
42
42
|
ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
|
|
43
43
|
ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
|
|
44
|
-
ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
|
|
45
|
-
ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
|
|
46
44
|
ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
|
|
47
45
|
ErrorType["NoParameter"] = "no-parameter";
|
|
48
46
|
ErrorType["NoAPIInfo"] = "no-api-info";
|
|
@@ -61,6 +59,9 @@ var WarningType;
|
|
|
61
59
|
WarningType["OperationOnlyContainsOptionalParam"] = "operation-only-contains-optional-param";
|
|
62
60
|
WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
|
|
63
61
|
WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
|
|
62
|
+
WarningType["OperationIdContainsSpecialCharacters"] = "operationid-contains-special-characters";
|
|
63
|
+
WarningType["UnsupportedAuthType"] = "unsupported-auth-type";
|
|
64
|
+
WarningType["GenerateJsonDataFailed"] = "generate-json-data-failed";
|
|
64
65
|
WarningType["Unknown"] = "unknown";
|
|
65
66
|
})(WarningType || (WarningType = {}));
|
|
66
67
|
/**
|
|
@@ -98,25 +99,23 @@ ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converte
|
|
|
98
99
|
ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
|
|
99
100
|
ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
|
|
100
101
|
ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
|
|
102
|
+
ConstantString.OperationIdContainsSpecialCharacters = "Operation id '%s' in OpenAPI description document contained special characters and was renamed to '%s'.";
|
|
103
|
+
ConstantString.AuthTypeIsNotSupported = "Unsupported authorization type in API '%s'. No authorization will be used.";
|
|
101
104
|
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
102
105
|
ConstantString.FuncDescriptionTooLong = "The description of the function '%s' is too long. The current length is %s characters, while the maximum allowed length is %s characters.";
|
|
106
|
+
ConstantString.GenerateJsonDataFailed = "Failed to generate JSON data for api: %s due to %s.";
|
|
103
107
|
ConstantString.WrappedCardVersion = "devPreview";
|
|
104
108
|
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
105
109
|
ConstantString.WrappedCardResponseLayout = "list";
|
|
106
110
|
ConstantString.GetMethod = "get";
|
|
107
111
|
ConstantString.PostMethod = "post";
|
|
108
112
|
ConstantString.AdaptiveCardVersion = "1.5";
|
|
109
|
-
ConstantString.AdaptiveCardSchema = "
|
|
113
|
+
ConstantString.AdaptiveCardSchema = "https://adaptivecards.io/schemas/adaptive-card.json";
|
|
110
114
|
ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
111
115
|
ConstantString.TextBlockType = "TextBlock";
|
|
112
116
|
ConstantString.ImageType = "Image";
|
|
113
117
|
ConstantString.ContainerType = "Container";
|
|
114
|
-
ConstantString.RegistrationIdPostfix =
|
|
115
|
-
apiKey: "REGISTRATION_ID",
|
|
116
|
-
oauth2: "CONFIGURATION_ID",
|
|
117
|
-
http: "REGISTRATION_ID",
|
|
118
|
-
openIdConnect: "REGISTRATION_ID",
|
|
119
|
-
};
|
|
118
|
+
ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
|
|
120
119
|
ConstantString.ResponseCodeFor20X = [
|
|
121
120
|
"200",
|
|
122
121
|
"201",
|
|
@@ -128,6 +127,7 @@ ConstantString.ResponseCodeFor20X = [
|
|
|
128
127
|
"207",
|
|
129
128
|
"208",
|
|
130
129
|
"226",
|
|
130
|
+
"2XX",
|
|
131
131
|
"default",
|
|
132
132
|
];
|
|
133
133
|
ConstantString.AllOperationMethods = [
|
|
@@ -193,16 +193,8 @@ class SpecParserError extends Error {
|
|
|
193
193
|
|
|
194
194
|
// Copyright (c) Microsoft Corporation.
|
|
195
195
|
class Utils {
|
|
196
|
-
static
|
|
197
|
-
|
|
198
|
-
for (const property in schema.properties) {
|
|
199
|
-
const nestedSchema = schema.properties[property];
|
|
200
|
-
if (nestedSchema.type === "object") {
|
|
201
|
-
return true;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
return false;
|
|
196
|
+
static isObjectSchema(schema) {
|
|
197
|
+
return schema.type === "object" || (!schema.type && !!schema.properties);
|
|
206
198
|
}
|
|
207
199
|
static containMultipleMediaTypes(bodyObject) {
|
|
208
200
|
return Object.keys((bodyObject === null || bodyObject === void 0 ? void 0 : bodyObject.content) || {}).length > 1;
|
|
@@ -213,11 +205,32 @@ class Utils {
|
|
|
213
205
|
static isAPIKeyAuth(authScheme) {
|
|
214
206
|
return authScheme.type === "apiKey";
|
|
215
207
|
}
|
|
208
|
+
static isAPIKeyAuthButNotInCookie(authScheme) {
|
|
209
|
+
return authScheme.type === "apiKey" && authScheme.in !== "cookie";
|
|
210
|
+
}
|
|
216
211
|
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
217
212
|
return !!(authScheme.type === "oauth2" &&
|
|
218
213
|
authScheme.flows &&
|
|
219
214
|
authScheme.flows.authorizationCode);
|
|
220
215
|
}
|
|
216
|
+
static isNotSupportedAuth(authSchemeArray) {
|
|
217
|
+
if (authSchemeArray.length === 0) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
for (const auths of authSchemeArray) {
|
|
224
|
+
if (auths.length === 1) {
|
|
225
|
+
if (Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme) ||
|
|
226
|
+
Utils.isBearerTokenAuth(auths[0].authScheme) ||
|
|
227
|
+
Utils.isAPIKeyAuthButNotInCookie(auths[0].authScheme)) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
221
234
|
static getAuthArray(securities, spec) {
|
|
222
235
|
var _a;
|
|
223
236
|
const result = [];
|
|
@@ -242,6 +255,20 @@ class Utils {
|
|
|
242
255
|
result.sort((a, b) => a[0].name.localeCompare(b[0].name));
|
|
243
256
|
return result;
|
|
244
257
|
}
|
|
258
|
+
static getAuthMap(spec) {
|
|
259
|
+
const authMap = {};
|
|
260
|
+
for (const url in spec.paths) {
|
|
261
|
+
for (const method in spec.paths[url]) {
|
|
262
|
+
const operation = spec.paths[url][method];
|
|
263
|
+
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
264
|
+
if (authArray && authArray.length > 0) {
|
|
265
|
+
const currentAuth = authArray[0][0];
|
|
266
|
+
authMap[operation.operationId] = currentAuth;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return authMap;
|
|
271
|
+
}
|
|
245
272
|
static getAuthInfo(spec) {
|
|
246
273
|
let authInfo = undefined;
|
|
247
274
|
for (const url in spec.paths) {
|
|
@@ -270,27 +297,33 @@ class Utils {
|
|
|
270
297
|
let multipleMediaType = false;
|
|
271
298
|
for (const code of ConstantString.ResponseCodeFor20X) {
|
|
272
299
|
const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
|
|
273
|
-
if (responseObject
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
else {
|
|
286
|
-
return { json, multipleMediaType };
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
300
|
+
if (!responseObject) {
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
multipleMediaType = Utils.containMultipleMediaTypes(responseObject);
|
|
304
|
+
if (!allowMultipleMediaType && multipleMediaType) {
|
|
305
|
+
json = {};
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
const mediaObj = Utils.getJsonContentType(responseObject);
|
|
309
|
+
if (Object.keys(mediaObj).length > 0) {
|
|
310
|
+
json = mediaObj;
|
|
311
|
+
return { json, multipleMediaType };
|
|
290
312
|
}
|
|
291
313
|
}
|
|
292
314
|
return { json, multipleMediaType };
|
|
293
315
|
}
|
|
316
|
+
static getJsonContentType(responseObject) {
|
|
317
|
+
if (responseObject.content) {
|
|
318
|
+
for (const contentType of Object.keys(responseObject.content)) {
|
|
319
|
+
// json media type can also be "application/json; charset=utf-8"
|
|
320
|
+
if (contentType.indexOf("application/json") >= 0) {
|
|
321
|
+
return responseObject.content[contentType];
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return {};
|
|
326
|
+
}
|
|
294
327
|
static convertPathToCamelCase(path) {
|
|
295
328
|
const pathSegments = path.split(/[./{]/);
|
|
296
329
|
const camelCaseSegments = pathSegments.map((segment) => {
|
|
@@ -326,7 +359,7 @@ class Utils {
|
|
|
326
359
|
}
|
|
327
360
|
return newStr;
|
|
328
361
|
}
|
|
329
|
-
static checkServerUrl(servers) {
|
|
362
|
+
static checkServerUrl(servers, allowHttp = false) {
|
|
330
363
|
const errors = [];
|
|
331
364
|
let serverUrl;
|
|
332
365
|
try {
|
|
@@ -349,8 +382,7 @@ class Utils {
|
|
|
349
382
|
data: servers,
|
|
350
383
|
});
|
|
351
384
|
}
|
|
352
|
-
else if (protocol !== "https:") {
|
|
353
|
-
// Http server url is not supported
|
|
385
|
+
else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
|
|
354
386
|
const protocolString = protocol.slice(0, -1);
|
|
355
387
|
errors.push({
|
|
356
388
|
type: ErrorType.UrlProtocolNotSupported,
|
|
@@ -366,10 +398,11 @@ class Utils {
|
|
|
366
398
|
let hasTopLevelServers = false;
|
|
367
399
|
let hasPathLevelServers = false;
|
|
368
400
|
let hasOperationLevelServers = false;
|
|
401
|
+
const allowHttp = options.projectType === ProjectType.Copilot;
|
|
369
402
|
if (spec.servers && spec.servers.length >= 1) {
|
|
370
403
|
hasTopLevelServers = true;
|
|
371
404
|
// for multiple server, we only use the first url
|
|
372
|
-
const serverErrors = Utils.checkServerUrl(spec.servers);
|
|
405
|
+
const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
|
|
373
406
|
errors.push(...serverErrors);
|
|
374
407
|
}
|
|
375
408
|
const paths = spec.paths;
|
|
@@ -377,7 +410,7 @@ class Utils {
|
|
|
377
410
|
const methods = paths[path];
|
|
378
411
|
if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
|
|
379
412
|
hasPathLevelServers = true;
|
|
380
|
-
const serverErrors = Utils.checkServerUrl(methods.servers);
|
|
413
|
+
const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
|
|
381
414
|
errors.push(...serverErrors);
|
|
382
415
|
}
|
|
383
416
|
for (const method in methods) {
|
|
@@ -385,7 +418,7 @@ class Utils {
|
|
|
385
418
|
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
|
|
386
419
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
387
420
|
hasOperationLevelServers = true;
|
|
388
|
-
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
421
|
+
const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
|
|
389
422
|
errors.push(...serverErrors);
|
|
390
423
|
}
|
|
391
424
|
}
|
|
@@ -432,7 +465,7 @@ class Utils {
|
|
|
432
465
|
optionalParams.push(parameter);
|
|
433
466
|
}
|
|
434
467
|
}
|
|
435
|
-
else if (schema
|
|
468
|
+
else if (Utils.isObjectSchema(schema)) {
|
|
436
469
|
const { properties } = schema;
|
|
437
470
|
for (const property in properties) {
|
|
438
471
|
let isRequired = false;
|
|
@@ -546,29 +579,6 @@ class Utils {
|
|
|
546
579
|
const serverUrl = operationServer || methodServer || rootServer;
|
|
547
580
|
return serverUrl;
|
|
548
581
|
}
|
|
549
|
-
static limitACBodyProperties(body, maxCount) {
|
|
550
|
-
const result = [];
|
|
551
|
-
let currentCount = 0;
|
|
552
|
-
for (const element of body) {
|
|
553
|
-
if (element.type === ConstantString.ContainerType) {
|
|
554
|
-
const items = this.limitACBodyProperties(element.items, maxCount - currentCount);
|
|
555
|
-
result.push({
|
|
556
|
-
type: ConstantString.ContainerType,
|
|
557
|
-
$data: element.$data,
|
|
558
|
-
items: items,
|
|
559
|
-
});
|
|
560
|
-
currentCount += items.length;
|
|
561
|
-
}
|
|
562
|
-
else {
|
|
563
|
-
result.push(element);
|
|
564
|
-
currentCount++;
|
|
565
|
-
}
|
|
566
|
-
if (currentCount >= maxCount) {
|
|
567
|
-
break;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
return result;
|
|
571
|
-
}
|
|
572
582
|
}
|
|
573
583
|
|
|
574
584
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -697,22 +707,6 @@ class Validator {
|
|
|
697
707
|
}
|
|
698
708
|
return result;
|
|
699
709
|
}
|
|
700
|
-
validateResponse(method, path) {
|
|
701
|
-
const result = { isValid: true, reason: [] };
|
|
702
|
-
const operationObject = this.spec.paths[path][method];
|
|
703
|
-
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
704
|
-
if (this.options.projectType === ProjectType.SME) {
|
|
705
|
-
// only support response body only contains “application/json” content type
|
|
706
|
-
if (multipleMediaType) {
|
|
707
|
-
result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
|
|
708
|
-
}
|
|
709
|
-
else if (Object.keys(json).length === 0) {
|
|
710
|
-
// response body should not be empty
|
|
711
|
-
result.reason.push(ErrorType.ResponseJsonIsEmpty);
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
return result;
|
|
715
|
-
}
|
|
716
710
|
validateServer(method, path) {
|
|
717
711
|
const result = { isValid: true, reason: [] };
|
|
718
712
|
const serverObj = Utils.getServerObject(this.spec, method, path);
|
|
@@ -721,8 +715,8 @@ class Validator {
|
|
|
721
715
|
result.reason.push(ErrorType.NoServerInformation);
|
|
722
716
|
}
|
|
723
717
|
else {
|
|
724
|
-
|
|
725
|
-
const serverValidateResult = Utils.checkServerUrl([serverObj]);
|
|
718
|
+
const allowHttp = this.projectType === ProjectType.Copilot;
|
|
719
|
+
const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
|
|
726
720
|
result.reason.push(...serverValidateResult.map((item) => item.type));
|
|
727
721
|
}
|
|
728
722
|
return result;
|
|
@@ -745,6 +739,9 @@ class Validator {
|
|
|
745
739
|
reason: [ErrorType.MultipleAuthNotSupported],
|
|
746
740
|
};
|
|
747
741
|
}
|
|
742
|
+
if (this.projectType === ProjectType.Copilot) {
|
|
743
|
+
return { isValid: true, reason: [] };
|
|
744
|
+
}
|
|
748
745
|
for (const auths of authSchemeArray) {
|
|
749
746
|
if (auths.length === 1) {
|
|
750
747
|
if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
|
|
@@ -757,125 +754,6 @@ class Validator {
|
|
|
757
754
|
}
|
|
758
755
|
return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
|
|
759
756
|
}
|
|
760
|
-
checkPostBodySchema(schema, isRequired = false) {
|
|
761
|
-
var _a;
|
|
762
|
-
const paramResult = {
|
|
763
|
-
requiredNum: 0,
|
|
764
|
-
optionalNum: 0,
|
|
765
|
-
isValid: true,
|
|
766
|
-
reason: [],
|
|
767
|
-
};
|
|
768
|
-
if (Object.keys(schema).length === 0) {
|
|
769
|
-
return paramResult;
|
|
770
|
-
}
|
|
771
|
-
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
772
|
-
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
773
|
-
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
774
|
-
paramResult.isValid = false;
|
|
775
|
-
paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
|
|
776
|
-
return paramResult;
|
|
777
|
-
}
|
|
778
|
-
if (schema.type === "string" ||
|
|
779
|
-
schema.type === "integer" ||
|
|
780
|
-
schema.type === "boolean" ||
|
|
781
|
-
schema.type === "number") {
|
|
782
|
-
if (isRequiredWithoutDefault) {
|
|
783
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
784
|
-
}
|
|
785
|
-
else {
|
|
786
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
else if (schema.type === "object") {
|
|
790
|
-
const { properties } = schema;
|
|
791
|
-
for (const property in properties) {
|
|
792
|
-
let isRequired = false;
|
|
793
|
-
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
794
|
-
isRequired = true;
|
|
795
|
-
}
|
|
796
|
-
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
797
|
-
paramResult.requiredNum += result.requiredNum;
|
|
798
|
-
paramResult.optionalNum += result.optionalNum;
|
|
799
|
-
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
800
|
-
paramResult.reason.push(...result.reason);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
else {
|
|
804
|
-
if (isRequiredWithoutDefault && !isCopilot) {
|
|
805
|
-
paramResult.isValid = false;
|
|
806
|
-
paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
return paramResult;
|
|
810
|
-
}
|
|
811
|
-
checkParamSchema(paramObject) {
|
|
812
|
-
const paramResult = {
|
|
813
|
-
requiredNum: 0,
|
|
814
|
-
optionalNum: 0,
|
|
815
|
-
isValid: true,
|
|
816
|
-
reason: [],
|
|
817
|
-
};
|
|
818
|
-
if (!paramObject) {
|
|
819
|
-
return paramResult;
|
|
820
|
-
}
|
|
821
|
-
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
822
|
-
for (let i = 0; i < paramObject.length; i++) {
|
|
823
|
-
const param = paramObject[i];
|
|
824
|
-
const schema = param.schema;
|
|
825
|
-
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
826
|
-
paramResult.isValid = false;
|
|
827
|
-
paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
|
|
828
|
-
continue;
|
|
829
|
-
}
|
|
830
|
-
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
831
|
-
if (isCopilot) {
|
|
832
|
-
if (isRequiredWithoutDefault) {
|
|
833
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
834
|
-
}
|
|
835
|
-
else {
|
|
836
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
837
|
-
}
|
|
838
|
-
continue;
|
|
839
|
-
}
|
|
840
|
-
if (param.in === "header" || param.in === "cookie") {
|
|
841
|
-
if (isRequiredWithoutDefault) {
|
|
842
|
-
paramResult.isValid = false;
|
|
843
|
-
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
844
|
-
}
|
|
845
|
-
continue;
|
|
846
|
-
}
|
|
847
|
-
if (schema.type !== "boolean" &&
|
|
848
|
-
schema.type !== "string" &&
|
|
849
|
-
schema.type !== "number" &&
|
|
850
|
-
schema.type !== "integer") {
|
|
851
|
-
if (isRequiredWithoutDefault) {
|
|
852
|
-
paramResult.isValid = false;
|
|
853
|
-
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
854
|
-
}
|
|
855
|
-
continue;
|
|
856
|
-
}
|
|
857
|
-
if (param.in === "query" || param.in === "path") {
|
|
858
|
-
if (isRequiredWithoutDefault) {
|
|
859
|
-
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
860
|
-
}
|
|
861
|
-
else {
|
|
862
|
-
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
return paramResult;
|
|
867
|
-
}
|
|
868
|
-
hasNestedObjectInSchema(schema) {
|
|
869
|
-
if (schema.type === "object") {
|
|
870
|
-
for (const property in schema.properties) {
|
|
871
|
-
const nestedSchema = schema.properties[property];
|
|
872
|
-
if (nestedSchema.type === "object") {
|
|
873
|
-
return true;
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
return false;
|
|
878
|
-
}
|
|
879
757
|
}
|
|
880
758
|
|
|
881
759
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -885,7 +763,6 @@ class CopilotValidator extends Validator {
|
|
|
885
763
|
this.projectType = ProjectType.Copilot;
|
|
886
764
|
this.options = options;
|
|
887
765
|
this.spec = spec;
|
|
888
|
-
this.checkCircularReference();
|
|
889
766
|
}
|
|
890
767
|
validateSpec() {
|
|
891
768
|
const result = { errors: [], warnings: [] };
|
|
@@ -911,10 +788,6 @@ class CopilotValidator extends Validator {
|
|
|
911
788
|
if (!methodAndPathResult.isValid) {
|
|
912
789
|
return methodAndPathResult;
|
|
913
790
|
}
|
|
914
|
-
const circularReferenceResult = this.validateCircularReference(method, path);
|
|
915
|
-
if (!circularReferenceResult.isValid) {
|
|
916
|
-
return circularReferenceResult;
|
|
917
|
-
}
|
|
918
791
|
const operationObject = this.spec.paths[path][method];
|
|
919
792
|
// validate auth
|
|
920
793
|
const authCheckResult = this.validateAuth(method, path);
|
|
@@ -926,24 +799,6 @@ class CopilotValidator extends Validator {
|
|
|
926
799
|
// validate server
|
|
927
800
|
const validateServerResult = this.validateServer(method, path);
|
|
928
801
|
result.reason.push(...validateServerResult.reason);
|
|
929
|
-
// validate response
|
|
930
|
-
const validateResponseResult = this.validateResponse(method, path);
|
|
931
|
-
result.reason.push(...validateResponseResult.reason);
|
|
932
|
-
// validate requestBody
|
|
933
|
-
const requestBody = operationObject.requestBody;
|
|
934
|
-
const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
|
|
935
|
-
if (requestJsonBody) {
|
|
936
|
-
const requestBodySchema = requestJsonBody.schema;
|
|
937
|
-
if (requestBodySchema.type !== "object") {
|
|
938
|
-
result.reason.push(ErrorType.PostBodySchemaIsNotJson);
|
|
939
|
-
}
|
|
940
|
-
const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
|
|
941
|
-
result.reason.push(...requestBodyParamResult.reason);
|
|
942
|
-
}
|
|
943
|
-
// validate parameters
|
|
944
|
-
const paramObject = operationObject.parameters;
|
|
945
|
-
const paramResult = this.checkParamSchema(paramObject);
|
|
946
|
-
result.reason.push(...paramResult.reason);
|
|
947
802
|
if (result.reason.length > 0) {
|
|
948
803
|
result.isValid = false;
|
|
949
804
|
}
|
|
@@ -1035,6 +890,108 @@ class SMEValidator extends Validator {
|
|
|
1035
890
|
}
|
|
1036
891
|
return result;
|
|
1037
892
|
}
|
|
893
|
+
validateResponse(method, path) {
|
|
894
|
+
const result = { isValid: true, reason: [] };
|
|
895
|
+
const operationObject = this.spec.paths[path][method];
|
|
896
|
+
const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
|
|
897
|
+
// only support response body only contains “application/json” content type
|
|
898
|
+
if (multipleMediaType) {
|
|
899
|
+
result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
|
|
900
|
+
}
|
|
901
|
+
else if (Object.keys(json).length === 0) {
|
|
902
|
+
// response body should not be empty
|
|
903
|
+
result.reason.push(ErrorType.ResponseJsonIsEmpty);
|
|
904
|
+
}
|
|
905
|
+
return result;
|
|
906
|
+
}
|
|
907
|
+
checkPostBodySchema(schema, isRequired = false) {
|
|
908
|
+
var _a;
|
|
909
|
+
const paramResult = {
|
|
910
|
+
requiredNum: 0,
|
|
911
|
+
optionalNum: 0,
|
|
912
|
+
isValid: true,
|
|
913
|
+
reason: [],
|
|
914
|
+
};
|
|
915
|
+
if (Object.keys(schema).length === 0) {
|
|
916
|
+
return paramResult;
|
|
917
|
+
}
|
|
918
|
+
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
919
|
+
const isCopilot = this.projectType === ProjectType.Copilot;
|
|
920
|
+
if (schema.type === "string" ||
|
|
921
|
+
schema.type === "integer" ||
|
|
922
|
+
schema.type === "boolean" ||
|
|
923
|
+
schema.type === "number") {
|
|
924
|
+
if (isRequiredWithoutDefault) {
|
|
925
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
926
|
+
}
|
|
927
|
+
else {
|
|
928
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
else if (Utils.isObjectSchema(schema)) {
|
|
932
|
+
const { properties } = schema;
|
|
933
|
+
for (const property in properties) {
|
|
934
|
+
let isRequired = false;
|
|
935
|
+
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
936
|
+
isRequired = true;
|
|
937
|
+
}
|
|
938
|
+
const result = this.checkPostBodySchema(properties[property], isRequired);
|
|
939
|
+
paramResult.requiredNum += result.requiredNum;
|
|
940
|
+
paramResult.optionalNum += result.optionalNum;
|
|
941
|
+
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
942
|
+
paramResult.reason.push(...result.reason);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
else {
|
|
946
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
947
|
+
paramResult.isValid = false;
|
|
948
|
+
paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
return paramResult;
|
|
952
|
+
}
|
|
953
|
+
checkParamSchema(paramObject) {
|
|
954
|
+
const paramResult = {
|
|
955
|
+
requiredNum: 0,
|
|
956
|
+
optionalNum: 0,
|
|
957
|
+
isValid: true,
|
|
958
|
+
reason: [],
|
|
959
|
+
};
|
|
960
|
+
if (!paramObject) {
|
|
961
|
+
return paramResult;
|
|
962
|
+
}
|
|
963
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
964
|
+
const param = paramObject[i];
|
|
965
|
+
const schema = param.schema;
|
|
966
|
+
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
967
|
+
if (param.in === "header" || param.in === "cookie") {
|
|
968
|
+
if (isRequiredWithoutDefault) {
|
|
969
|
+
paramResult.isValid = false;
|
|
970
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
971
|
+
}
|
|
972
|
+
continue;
|
|
973
|
+
}
|
|
974
|
+
if (schema.type !== "boolean" &&
|
|
975
|
+
schema.type !== "string" &&
|
|
976
|
+
schema.type !== "number" &&
|
|
977
|
+
schema.type !== "integer") {
|
|
978
|
+
if (isRequiredWithoutDefault) {
|
|
979
|
+
paramResult.isValid = false;
|
|
980
|
+
paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
|
|
981
|
+
}
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
984
|
+
if (param.in === "query" || param.in === "path") {
|
|
985
|
+
if (isRequiredWithoutDefault) {
|
|
986
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
987
|
+
}
|
|
988
|
+
else {
|
|
989
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
return paramResult;
|
|
994
|
+
}
|
|
1038
995
|
validateParamCount(postBodyResult, paramResult) {
|
|
1039
996
|
const result = { isValid: true, reason: [] };
|
|
1040
997
|
const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;
|
|
@@ -1312,20 +1269,157 @@ class SpecFilter {
|
|
|
1312
1269
|
}
|
|
1313
1270
|
}
|
|
1314
1271
|
|
|
1272
|
+
// Copyright (c) Microsoft Corporation.
|
|
1273
|
+
class JsonDataGenerator {
|
|
1274
|
+
static generate(schema) {
|
|
1275
|
+
return this.generateMockData(schema);
|
|
1276
|
+
}
|
|
1277
|
+
static generateMockData(schema) {
|
|
1278
|
+
if (this.visitedSchemas.has(schema)) {
|
|
1279
|
+
return null; // Prevent circular reference
|
|
1280
|
+
}
|
|
1281
|
+
this.visitedSchemas.add(schema);
|
|
1282
|
+
let result;
|
|
1283
|
+
if (schema.anyOf) {
|
|
1284
|
+
// Select the first schema in anyOf
|
|
1285
|
+
const selectedSchema = schema.anyOf[0];
|
|
1286
|
+
result = this.generateMockData(selectedSchema);
|
|
1287
|
+
}
|
|
1288
|
+
else if (schema.oneOf) {
|
|
1289
|
+
// Select the first schema in oneOf
|
|
1290
|
+
const selectedSchema = schema.oneOf[0];
|
|
1291
|
+
result = this.generateMockData(selectedSchema);
|
|
1292
|
+
}
|
|
1293
|
+
else if (schema.allOf) {
|
|
1294
|
+
// merge all schemas in allOf
|
|
1295
|
+
result = {};
|
|
1296
|
+
for (const subschema of schema.allOf) {
|
|
1297
|
+
const data = this.generateMockData(subschema);
|
|
1298
|
+
result = Object.assign(Object.assign({}, result), data);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
else {
|
|
1302
|
+
switch (schema.type) {
|
|
1303
|
+
case "string":
|
|
1304
|
+
if (schema.example !== undefined) {
|
|
1305
|
+
result = schema.example;
|
|
1306
|
+
}
|
|
1307
|
+
else if (schema.format) {
|
|
1308
|
+
switch (schema.format) {
|
|
1309
|
+
case "date-time":
|
|
1310
|
+
result = "2024-11-01T05:25:43.593Z";
|
|
1311
|
+
break;
|
|
1312
|
+
case "email":
|
|
1313
|
+
result = "example@example.com";
|
|
1314
|
+
break;
|
|
1315
|
+
case "uuid":
|
|
1316
|
+
result = "123e4567-e89b-12d3-a456-426614174000";
|
|
1317
|
+
break;
|
|
1318
|
+
case "ipv4":
|
|
1319
|
+
result = "192.168.0.1";
|
|
1320
|
+
break;
|
|
1321
|
+
case "ipv6":
|
|
1322
|
+
result = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
|
|
1323
|
+
break;
|
|
1324
|
+
default:
|
|
1325
|
+
result = "example string";
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
else {
|
|
1329
|
+
result = "example string";
|
|
1330
|
+
}
|
|
1331
|
+
break;
|
|
1332
|
+
case "number":
|
|
1333
|
+
if (schema.example !== undefined) {
|
|
1334
|
+
result = schema.example;
|
|
1335
|
+
}
|
|
1336
|
+
else if (schema.format) {
|
|
1337
|
+
switch (schema.format) {
|
|
1338
|
+
case "float":
|
|
1339
|
+
result = 3.14;
|
|
1340
|
+
break;
|
|
1341
|
+
case "double":
|
|
1342
|
+
result = 3.14159;
|
|
1343
|
+
break;
|
|
1344
|
+
default:
|
|
1345
|
+
result = 123;
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
else {
|
|
1349
|
+
result = 123;
|
|
1350
|
+
}
|
|
1351
|
+
break;
|
|
1352
|
+
case "integer":
|
|
1353
|
+
if (schema.example !== undefined) {
|
|
1354
|
+
result = schema.example;
|
|
1355
|
+
}
|
|
1356
|
+
else if (schema.format) {
|
|
1357
|
+
switch (schema.format) {
|
|
1358
|
+
case "int32":
|
|
1359
|
+
result = 123456;
|
|
1360
|
+
break;
|
|
1361
|
+
case "int64":
|
|
1362
|
+
result = 123456789;
|
|
1363
|
+
break;
|
|
1364
|
+
default:
|
|
1365
|
+
result = 123;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
else {
|
|
1369
|
+
result = 123;
|
|
1370
|
+
}
|
|
1371
|
+
break;
|
|
1372
|
+
case "boolean":
|
|
1373
|
+
result = schema.example !== undefined ? schema.example : true;
|
|
1374
|
+
break;
|
|
1375
|
+
case "array":
|
|
1376
|
+
result = [this.generateMockData(schema.items)];
|
|
1377
|
+
break;
|
|
1378
|
+
case "object":
|
|
1379
|
+
result = {};
|
|
1380
|
+
if (schema.properties) {
|
|
1381
|
+
for (const key in schema.properties) {
|
|
1382
|
+
result[key] = this.generateMockData(schema.properties[key]);
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
break;
|
|
1386
|
+
default:
|
|
1387
|
+
result = schema.example || null;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
this.visitedSchemas.delete(schema);
|
|
1391
|
+
return result;
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
JsonDataGenerator.visitedSchemas = new Set();
|
|
1395
|
+
|
|
1315
1396
|
// Copyright (c) Microsoft Corporation.
|
|
1316
1397
|
class AdaptiveCardGenerator {
|
|
1317
|
-
static generateAdaptiveCard(operationItem, allowMultipleMediaType = false) {
|
|
1398
|
+
static generateAdaptiveCard(operationItem, allowMultipleMediaType = false, maxElementCount = Number.MAX_SAFE_INTEGER) {
|
|
1318
1399
|
try {
|
|
1319
1400
|
const { json } = Utils.getResponseJson(operationItem, allowMultipleMediaType);
|
|
1320
1401
|
let cardBody = [];
|
|
1402
|
+
let jsonData = {};
|
|
1403
|
+
const warnings = [];
|
|
1404
|
+
const operationId = operationItem.operationId;
|
|
1321
1405
|
let schema = json.schema;
|
|
1322
1406
|
let jsonPath = "$";
|
|
1323
1407
|
if (schema && Object.keys(schema).length > 0) {
|
|
1408
|
+
try {
|
|
1409
|
+
jsonData = JsonDataGenerator.generate(schema);
|
|
1410
|
+
}
|
|
1411
|
+
catch (err) {
|
|
1412
|
+
warnings.push({
|
|
1413
|
+
type: WarningType.GenerateJsonDataFailed,
|
|
1414
|
+
content: Utils.format(ConstantString.GenerateJsonDataFailed, operationId, err.toString()),
|
|
1415
|
+
data: operationId,
|
|
1416
|
+
});
|
|
1417
|
+
}
|
|
1324
1418
|
jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
|
|
1325
1419
|
if (jsonPath !== "$") {
|
|
1326
1420
|
schema = schema.properties[jsonPath];
|
|
1327
1421
|
}
|
|
1328
|
-
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
|
|
1422
|
+
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "", "", maxElementCount);
|
|
1329
1423
|
}
|
|
1330
1424
|
// if no schema, try to use example value
|
|
1331
1425
|
if (cardBody.length === 0 && (json.examples || json.example)) {
|
|
@@ -1353,16 +1447,20 @@ class AdaptiveCardGenerator {
|
|
|
1353
1447
|
version: ConstantString.AdaptiveCardVersion,
|
|
1354
1448
|
body: cardBody,
|
|
1355
1449
|
};
|
|
1356
|
-
return [fullCard, jsonPath];
|
|
1450
|
+
return [fullCard, jsonPath, jsonData, warnings];
|
|
1357
1451
|
}
|
|
1358
1452
|
catch (err) {
|
|
1359
1453
|
throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
|
|
1360
1454
|
}
|
|
1361
1455
|
}
|
|
1362
|
-
static generateCardFromResponse(schema, name, parentArrayName = "") {
|
|
1456
|
+
static generateCardFromResponse(schema, name, parentArrayName = "", maxElementCount = Number.MAX_SAFE_INTEGER, counter = { count: 0 }) {
|
|
1457
|
+
if (counter.count >= maxElementCount) {
|
|
1458
|
+
return [];
|
|
1459
|
+
}
|
|
1363
1460
|
if (schema.type === "array") {
|
|
1364
1461
|
// schema.items can be arbitrary object: schema { type: array, items: {} }
|
|
1365
1462
|
if (Object.keys(schema.items).length === 0) {
|
|
1463
|
+
counter.count++;
|
|
1366
1464
|
return [
|
|
1367
1465
|
{
|
|
1368
1466
|
type: ConstantString.TextBlockType,
|
|
@@ -1371,7 +1469,7 @@ class AdaptiveCardGenerator {
|
|
|
1371
1469
|
},
|
|
1372
1470
|
];
|
|
1373
1471
|
}
|
|
1374
|
-
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
|
|
1472
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name, maxElementCount, counter);
|
|
1375
1473
|
const template = {
|
|
1376
1474
|
type: ConstantString.ContainerType,
|
|
1377
1475
|
$data: name ? `\${${name}}` : "${$root}",
|
|
@@ -1381,11 +1479,11 @@ class AdaptiveCardGenerator {
|
|
|
1381
1479
|
return [template];
|
|
1382
1480
|
}
|
|
1383
1481
|
// some schema may not contain type but contain properties
|
|
1384
|
-
if (
|
|
1482
|
+
if (Utils.isObjectSchema(schema)) {
|
|
1385
1483
|
const { properties } = schema;
|
|
1386
1484
|
const result = [];
|
|
1387
1485
|
for (const property in properties) {
|
|
1388
|
-
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
|
|
1486
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName, maxElementCount, counter);
|
|
1389
1487
|
result.push(...obj);
|
|
1390
1488
|
}
|
|
1391
1489
|
if (schema.additionalProperties) {
|
|
@@ -1398,6 +1496,7 @@ class AdaptiveCardGenerator {
|
|
|
1398
1496
|
schema.type === "integer" ||
|
|
1399
1497
|
schema.type === "boolean" ||
|
|
1400
1498
|
schema.type === "number") {
|
|
1499
|
+
counter.count++;
|
|
1401
1500
|
if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
|
|
1402
1501
|
// string in root: "ddd"
|
|
1403
1502
|
let text = "result: ${$root}";
|
|
@@ -1422,24 +1521,17 @@ class AdaptiveCardGenerator {
|
|
|
1422
1521
|
];
|
|
1423
1522
|
}
|
|
1424
1523
|
else {
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
{
|
|
1437
|
-
type: "Image",
|
|
1438
|
-
url: "${$data}",
|
|
1439
|
-
$when: "${$data != null && $data != ''}",
|
|
1440
|
-
},
|
|
1441
|
-
];
|
|
1442
|
-
}
|
|
1524
|
+
const url = name ? `\${${name}}` : "${$data}";
|
|
1525
|
+
const condition = name
|
|
1526
|
+
? `\${${name} != null && ${name} != ''}`
|
|
1527
|
+
: "${$data != null && $data != ''}";
|
|
1528
|
+
return [
|
|
1529
|
+
{
|
|
1530
|
+
type: "Image",
|
|
1531
|
+
url,
|
|
1532
|
+
$when: condition,
|
|
1533
|
+
},
|
|
1534
|
+
];
|
|
1443
1535
|
}
|
|
1444
1536
|
}
|
|
1445
1537
|
if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
|
|
@@ -1449,7 +1541,7 @@ class AdaptiveCardGenerator {
|
|
|
1449
1541
|
}
|
|
1450
1542
|
// Find the first array property in the response schema object with the well-known name
|
|
1451
1543
|
static getResponseJsonPathFromSchema(schema) {
|
|
1452
|
-
if (
|
|
1544
|
+
if (Utils.isObjectSchema(schema)) {
|
|
1453
1545
|
const { properties } = schema;
|
|
1454
1546
|
for (const property in properties) {
|
|
1455
1547
|
const schema = properties[property];
|
|
@@ -1601,7 +1693,7 @@ function inferProperties(card) {
|
|
|
1601
1693
|
|
|
1602
1694
|
// Copyright (c) Microsoft Corporation.
|
|
1603
1695
|
class ManifestUpdater {
|
|
1604
|
-
static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options,
|
|
1696
|
+
static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authMap, existingPluginManifestInfo) {
|
|
1605
1697
|
const manifest = await fs.readJSON(manifestPath);
|
|
1606
1698
|
const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
|
|
1607
1699
|
const useCopilotExtensionsInSchema = await ManifestUtil.useCopilotExtensionsInSchema(manifest);
|
|
@@ -1631,7 +1723,7 @@ class ManifestUpdater {
|
|
|
1631
1723
|
}
|
|
1632
1724
|
const appName = this.removeEnvs(manifest.name.short);
|
|
1633
1725
|
const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
|
|
1634
|
-
const [apiPlugin, warnings] = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName,
|
|
1726
|
+
const [apiPlugin, warnings] = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo);
|
|
1635
1727
|
return [manifest, apiPlugin, warnings];
|
|
1636
1728
|
}
|
|
1637
1729
|
static updateManifestDescription(manifest, spec) {
|
|
@@ -1653,28 +1745,13 @@ class ManifestUpdater {
|
|
|
1653
1745
|
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), ErrorType.UpdateManifestFailed);
|
|
1654
1746
|
}
|
|
1655
1747
|
}
|
|
1656
|
-
static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName,
|
|
1748
|
+
static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo) {
|
|
1657
1749
|
var _a, _b, _c, _d;
|
|
1658
1750
|
const warnings = [];
|
|
1659
1751
|
const functions = [];
|
|
1660
|
-
const
|
|
1752
|
+
const functionNamesMap = {};
|
|
1661
1753
|
const conversationStarters = [];
|
|
1662
1754
|
const paths = spec.paths;
|
|
1663
|
-
const pluginAuthObj = {
|
|
1664
|
-
type: "None",
|
|
1665
|
-
};
|
|
1666
|
-
if (authInfo) {
|
|
1667
|
-
if (Utils.isOAuthWithAuthCodeFlow(authInfo.authScheme)) {
|
|
1668
|
-
pluginAuthObj.type = "OAuthPluginVault";
|
|
1669
|
-
}
|
|
1670
|
-
else if (Utils.isBearerTokenAuth(authInfo.authScheme)) {
|
|
1671
|
-
pluginAuthObj.type = "ApiKeyPluginVault";
|
|
1672
|
-
}
|
|
1673
|
-
if (pluginAuthObj.type !== "None") {
|
|
1674
|
-
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
|
|
1675
|
-
pluginAuthObj.reference_id = `\${{${safeRegistrationIdName}}}`;
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1678
1755
|
for (const pathUrl in paths) {
|
|
1679
1756
|
const pathItem = paths[pathUrl];
|
|
1680
1757
|
if (pathItem) {
|
|
@@ -1682,36 +1759,11 @@ class ManifestUpdater {
|
|
|
1682
1759
|
for (const method in operations) {
|
|
1683
1760
|
if (options.allowMethods.includes(method)) {
|
|
1684
1761
|
const operationItem = operations[method];
|
|
1685
|
-
const confirmationBodies = [];
|
|
1686
1762
|
if (operationItem) {
|
|
1687
1763
|
const operationId = operationItem.operationId;
|
|
1688
1764
|
const safeFunctionName = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1689
1765
|
const description = (_a = operationItem.description) !== null && _a !== void 0 ? _a : "";
|
|
1690
1766
|
const summary = operationItem.summary;
|
|
1691
|
-
const paramObject = operationItem.parameters;
|
|
1692
|
-
const requestBody = operationItem.requestBody;
|
|
1693
|
-
if (paramObject) {
|
|
1694
|
-
for (let i = 0; i < paramObject.length; i++) {
|
|
1695
|
-
const param = paramObject[i];
|
|
1696
|
-
const schema = param.schema;
|
|
1697
|
-
ManifestUpdater.checkSchema(schema, method, pathUrl);
|
|
1698
|
-
confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(param.name));
|
|
1699
|
-
}
|
|
1700
|
-
}
|
|
1701
|
-
if (requestBody) {
|
|
1702
|
-
const requestJsonBody = requestBody.content["application/json"];
|
|
1703
|
-
const requestBodySchema = requestJsonBody.schema;
|
|
1704
|
-
if (requestBodySchema.type === "object") {
|
|
1705
|
-
for (const property in requestBodySchema.properties) {
|
|
1706
|
-
const schema = requestBodySchema.properties[property];
|
|
1707
|
-
ManifestUpdater.checkSchema(schema, method, pathUrl);
|
|
1708
|
-
confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(property));
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
else {
|
|
1712
|
-
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
|
|
1713
|
-
}
|
|
1714
|
-
}
|
|
1715
1767
|
let funcDescription = operationItem.description || operationItem.summary || "";
|
|
1716
1768
|
if (funcDescription.length > ConstantString.FunctionDescriptionMaxLens) {
|
|
1717
1769
|
warnings.push({
|
|
@@ -1729,8 +1781,7 @@ class ManifestUpdater {
|
|
|
1729
1781
|
try {
|
|
1730
1782
|
const { json } = Utils.getResponseJson(operationItem);
|
|
1731
1783
|
if (json.schema) {
|
|
1732
|
-
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operationItem);
|
|
1733
|
-
card.body = Utils.limitACBodyProperties(card.body, 5);
|
|
1784
|
+
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operationItem, false, 5);
|
|
1734
1785
|
const responseSemantic = wrapResponseSemantics(card, jsonPath);
|
|
1735
1786
|
funcObj.capabilities = {
|
|
1736
1787
|
response_semantics: responseSemantic,
|
|
@@ -1746,19 +1797,66 @@ class ManifestUpdater {
|
|
|
1746
1797
|
}
|
|
1747
1798
|
}
|
|
1748
1799
|
if (options.allowConfirmation && method !== ConstantString.GetMethod) {
|
|
1749
|
-
|
|
1750
|
-
|
|
1800
|
+
const paramObject = operationItem.parameters;
|
|
1801
|
+
const requestBody = operationItem.requestBody;
|
|
1802
|
+
const confirmationBodies = [];
|
|
1803
|
+
if (paramObject) {
|
|
1804
|
+
for (let i = 0; i < paramObject.length; i++) {
|
|
1805
|
+
const param = paramObject[i];
|
|
1806
|
+
const schema = param.schema;
|
|
1807
|
+
ManifestUpdater.checkSchema(schema, method, pathUrl);
|
|
1808
|
+
confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(param.name));
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
if (requestBody) {
|
|
1812
|
+
const requestJsonBody = Utils.getJsonContentType(requestBody);
|
|
1813
|
+
const requestBodySchema = requestJsonBody.schema;
|
|
1814
|
+
if (Utils.isObjectSchema(requestBodySchema)) {
|
|
1815
|
+
for (const property in requestBodySchema.properties) {
|
|
1816
|
+
const schema = requestBodySchema.properties[property];
|
|
1817
|
+
ManifestUpdater.checkSchema(schema, method, pathUrl);
|
|
1818
|
+
confirmationBodies.push(ManifestUpdater.getConfirmationBodyItem(property));
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
else {
|
|
1822
|
+
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(requestBodySchema)), ErrorType.UpdateManifestFailed);
|
|
1823
|
+
}
|
|
1751
1824
|
}
|
|
1752
|
-
funcObj.capabilities.confirmation = {
|
|
1753
|
-
type: "AdaptiveCard",
|
|
1754
|
-
title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
|
|
1755
|
-
};
|
|
1756
1825
|
if (confirmationBodies.length > 0) {
|
|
1826
|
+
if (!funcObj.capabilities) {
|
|
1827
|
+
funcObj.capabilities = {};
|
|
1828
|
+
}
|
|
1829
|
+
funcObj.capabilities.confirmation = {
|
|
1830
|
+
type: "AdaptiveCard",
|
|
1831
|
+
title: (_b = operationItem.summary) !== null && _b !== void 0 ? _b : description,
|
|
1832
|
+
};
|
|
1757
1833
|
funcObj.capabilities.confirmation.body = confirmationBodies.join("\n");
|
|
1758
1834
|
}
|
|
1759
1835
|
}
|
|
1760
1836
|
functions.push(funcObj);
|
|
1761
|
-
|
|
1837
|
+
const authInfo = authMap[operationId];
|
|
1838
|
+
let key = "None";
|
|
1839
|
+
let authName = "None";
|
|
1840
|
+
if (authInfo) {
|
|
1841
|
+
if (Utils.isOAuthWithAuthCodeFlow(authInfo.authScheme)) {
|
|
1842
|
+
key = "OAuthPluginVault";
|
|
1843
|
+
authName = authInfo.name;
|
|
1844
|
+
}
|
|
1845
|
+
else if (Utils.isBearerTokenAuth(authInfo.authScheme) ||
|
|
1846
|
+
Utils.isAPIKeyAuthButNotInCookie(authInfo.authScheme)) {
|
|
1847
|
+
key = "ApiKeyPluginVault";
|
|
1848
|
+
authName = authInfo.name;
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
if (functionNamesMap[key]) {
|
|
1852
|
+
functionNamesMap[key].functionNames.push(safeFunctionName);
|
|
1853
|
+
}
|
|
1854
|
+
else {
|
|
1855
|
+
functionNamesMap[key] = {
|
|
1856
|
+
functionNames: [safeFunctionName],
|
|
1857
|
+
authName: authName,
|
|
1858
|
+
};
|
|
1859
|
+
}
|
|
1762
1860
|
const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
|
|
1763
1861
|
if (conversationStarterStr) {
|
|
1764
1862
|
conversationStarters.push(conversationStarterStr);
|
|
@@ -1768,6 +1866,12 @@ class ManifestUpdater {
|
|
|
1768
1866
|
}
|
|
1769
1867
|
}
|
|
1770
1868
|
}
|
|
1869
|
+
if (Object.keys(functionNamesMap).length === 0) {
|
|
1870
|
+
functionNamesMap["None"] = {
|
|
1871
|
+
functionNames: [],
|
|
1872
|
+
authName: "None",
|
|
1873
|
+
};
|
|
1874
|
+
}
|
|
1771
1875
|
let apiPlugin;
|
|
1772
1876
|
if (await fs.pathExists(apiPluginFilePath)) {
|
|
1773
1877
|
apiPlugin = await fs.readJSON(apiPluginFilePath);
|
|
@@ -1803,24 +1907,35 @@ class ManifestUpdater {
|
|
|
1803
1907
|
const relativePath = ManifestUpdater.getRelativePath(existingPluginManifestInfo.manifestPath, existingPluginManifestInfo.specPath);
|
|
1804
1908
|
apiPlugin.runtimes = apiPlugin.runtimes.filter((runtime) => runtime.spec.url !== relativePath);
|
|
1805
1909
|
}
|
|
1806
|
-
const
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1910
|
+
for (const authType in functionNamesMap) {
|
|
1911
|
+
const pluginAuthObj = {
|
|
1912
|
+
type: authType,
|
|
1913
|
+
};
|
|
1914
|
+
const authName = functionNamesMap[authType].authName;
|
|
1915
|
+
if (pluginAuthObj.type !== "None") {
|
|
1916
|
+
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authName}_${ConstantString.RegistrationIdPostfix}`);
|
|
1917
|
+
pluginAuthObj.reference_id = `\${{${safeRegistrationIdName}}}`;
|
|
1918
|
+
}
|
|
1919
|
+
const functionNamesInfo = functionNamesMap[authType];
|
|
1920
|
+
const index = apiPlugin.runtimes.findIndex((runtime) => {
|
|
1921
|
+
var _a, _b;
|
|
1922
|
+
return runtime.spec.url === specRelativePath &&
|
|
1923
|
+
runtime.type === "OpenApi" &&
|
|
1924
|
+
((_b = (_a = runtime.auth) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : "None") === authType;
|
|
1820
1925
|
});
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1926
|
+
if (index === -1) {
|
|
1927
|
+
apiPlugin.runtimes.push({
|
|
1928
|
+
type: "OpenApi",
|
|
1929
|
+
auth: pluginAuthObj,
|
|
1930
|
+
spec: {
|
|
1931
|
+
url: specRelativePath,
|
|
1932
|
+
},
|
|
1933
|
+
run_for_functions: functionNamesInfo.functionNames,
|
|
1934
|
+
});
|
|
1935
|
+
}
|
|
1936
|
+
else {
|
|
1937
|
+
apiPlugin.runtimes[index].run_for_functions = functionNamesInfo.functionNames;
|
|
1938
|
+
}
|
|
1824
1939
|
}
|
|
1825
1940
|
if (!apiPlugin.name_for_human) {
|
|
1826
1941
|
apiPlugin.name_for_human = appName;
|
|
@@ -1861,7 +1976,7 @@ class ManifestUpdater {
|
|
|
1861
1976
|
};
|
|
1862
1977
|
if (authInfo) {
|
|
1863
1978
|
const auth = authInfo.authScheme;
|
|
1864
|
-
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix
|
|
1979
|
+
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
|
|
1865
1980
|
if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
|
|
1866
1981
|
composeExtension.authorization = {
|
|
1867
1982
|
authType: "apiSecretServiceAuth",
|
|
@@ -1988,6 +2103,7 @@ class SpecParser {
|
|
|
1988
2103
|
};
|
|
1989
2104
|
this.pathOrSpec = pathOrDoc;
|
|
1990
2105
|
this.parser = new SwaggerParser();
|
|
2106
|
+
this.refParser = new $RefParser();
|
|
1991
2107
|
this.options = Object.assign(Object.assign({}, this.defaultOptions), (options !== null && options !== void 0 ? options : {}));
|
|
1992
2108
|
}
|
|
1993
2109
|
/**
|
|
@@ -2000,12 +2116,15 @@ class SpecParser {
|
|
|
2000
2116
|
let hash = "";
|
|
2001
2117
|
try {
|
|
2002
2118
|
await this.loadSpec();
|
|
2003
|
-
if (!this.
|
|
2119
|
+
if (!this.refParser.$refs.circular) {
|
|
2004
2120
|
await this.parser.validate(this.spec);
|
|
2005
2121
|
}
|
|
2006
2122
|
else {
|
|
2123
|
+
// The following code hangs for Graph API, support will be added when SwaggerParser is updated.
|
|
2124
|
+
/*
|
|
2007
2125
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
|
|
2008
2126
|
await this.parser.validate(clonedUnResolveSpec);
|
|
2127
|
+
*/
|
|
2009
2128
|
}
|
|
2010
2129
|
}
|
|
2011
2130
|
catch (e) {
|
|
@@ -2033,7 +2152,7 @@ class SpecParser {
|
|
|
2033
2152
|
};
|
|
2034
2153
|
}
|
|
2035
2154
|
// Remote reference not supported
|
|
2036
|
-
const refPaths = this.
|
|
2155
|
+
const refPaths = this.refParser.$refs.paths();
|
|
2037
2156
|
// refPaths [0] is the current spec file path
|
|
2038
2157
|
if (refPaths.length > 1) {
|
|
2039
2158
|
errors.push({
|
|
@@ -2162,7 +2281,7 @@ class SpecParser {
|
|
|
2162
2281
|
throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
|
|
2163
2282
|
}
|
|
2164
2283
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(newUnResolvedSpec));
|
|
2165
|
-
const newSpec =
|
|
2284
|
+
const newSpec = await this.deReferenceSpec(clonedUnResolveSpec);
|
|
2166
2285
|
return [newUnResolvedSpec, newSpec];
|
|
2167
2286
|
}
|
|
2168
2287
|
catch (err) {
|
|
@@ -2172,6 +2291,10 @@ class SpecParser {
|
|
|
2172
2291
|
throw new SpecParserError(err.toString(), ErrorType.GetSpecFailed);
|
|
2173
2292
|
}
|
|
2174
2293
|
}
|
|
2294
|
+
async deReferenceSpec(spec) {
|
|
2295
|
+
const result = await this.refParser.dereference(spec);
|
|
2296
|
+
return result;
|
|
2297
|
+
}
|
|
2175
2298
|
/**
|
|
2176
2299
|
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
2177
2300
|
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
@@ -2188,7 +2311,31 @@ class SpecParser {
|
|
|
2188
2311
|
const newSpecs = await this.getFilteredSpecs(filter, signal);
|
|
2189
2312
|
const newUnResolvedSpec = newSpecs[0];
|
|
2190
2313
|
const newSpec = newSpecs[1];
|
|
2191
|
-
const
|
|
2314
|
+
const paths = newUnResolvedSpec.paths;
|
|
2315
|
+
for (const pathUrl in paths) {
|
|
2316
|
+
const operations = paths[pathUrl];
|
|
2317
|
+
for (const method in operations) {
|
|
2318
|
+
const operationItem = operations[method];
|
|
2319
|
+
const operationId = operationItem.operationId;
|
|
2320
|
+
const containsSpecialCharacters = /[^a-zA-Z0-9_]/.test(operationId);
|
|
2321
|
+
if (containsSpecialCharacters) {
|
|
2322
|
+
operationItem.operationId = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
2323
|
+
result.warnings.push({
|
|
2324
|
+
type: WarningType.OperationIdContainsSpecialCharacters,
|
|
2325
|
+
content: Utils.format(ConstantString.OperationIdContainsSpecialCharacters, operationId, operationItem.operationId),
|
|
2326
|
+
data: operationId,
|
|
2327
|
+
});
|
|
2328
|
+
}
|
|
2329
|
+
const authArray = Utils.getAuthArray(operationItem.security, newSpec);
|
|
2330
|
+
if (Utils.isNotSupportedAuth(authArray)) {
|
|
2331
|
+
result.warnings.push({
|
|
2332
|
+
type: WarningType.UnsupportedAuthType,
|
|
2333
|
+
content: Utils.format(ConstantString.AuthTypeIsNotSupported, operationId),
|
|
2334
|
+
data: operationId,
|
|
2335
|
+
});
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2192
2339
|
await this.saveFilterSpec(outputSpecPath, newUnResolvedSpec);
|
|
2193
2340
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
2194
2341
|
throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
|
|
@@ -2199,7 +2346,8 @@ class SpecParser {
|
|
|
2199
2346
|
specPath: this.pathOrSpec,
|
|
2200
2347
|
}
|
|
2201
2348
|
: undefined;
|
|
2202
|
-
const
|
|
2349
|
+
const authMap = Utils.getAuthMap(newSpec);
|
|
2350
|
+
const [updatedManifest, apiPlugin, warnings] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authMap, existingPluginManifestInfo);
|
|
2203
2351
|
result.warnings.push(...warnings);
|
|
2204
2352
|
await fs.outputJSON(manifestPath, updatedManifest, { spaces: 4 });
|
|
2205
2353
|
await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 4 });
|
|
@@ -2240,13 +2388,14 @@ class SpecParser {
|
|
|
2240
2388
|
if (this.options.allowMethods.includes(method)) {
|
|
2241
2389
|
const operation = newSpec.paths[url][method];
|
|
2242
2390
|
try {
|
|
2243
|
-
const [card, jsonPath] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
|
|
2391
|
+
const [card, jsonPath, jsonData, warnings] = AdaptiveCardGenerator.generateAdaptiveCard(operation);
|
|
2392
|
+
result.warnings.push(...warnings);
|
|
2244
2393
|
const safeAdaptiveCardName = operation.operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
2245
2394
|
const fileName = path.join(adaptiveCardFolder, `${safeAdaptiveCardName}.json`);
|
|
2246
2395
|
const wrappedCard = wrapAdaptiveCard(card, jsonPath);
|
|
2247
2396
|
await fs.outputJSON(fileName, wrappedCard, { spaces: 2 });
|
|
2248
2397
|
const dataFileName = path.join(adaptiveCardFolder, `${safeAdaptiveCardName}.data.json`);
|
|
2249
|
-
await fs.outputJSON(dataFileName,
|
|
2398
|
+
await fs.outputJSON(dataFileName, jsonData, { spaces: 2 });
|
|
2250
2399
|
}
|
|
2251
2400
|
catch (err) {
|
|
2252
2401
|
result.allSuccess = false;
|
|
@@ -2286,7 +2435,7 @@ class SpecParser {
|
|
|
2286
2435
|
this.isSwaggerFile = true;
|
|
2287
2436
|
}
|
|
2288
2437
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
|
|
2289
|
-
this.spec =
|
|
2438
|
+
this.spec = await this.deReferenceSpec(clonedUnResolveSpec);
|
|
2290
2439
|
}
|
|
2291
2440
|
}
|
|
2292
2441
|
getAPIs(spec) {
|