@microsoft/m365-spec-parser 0.1.1-alpha.ebe783822.0 → 0.1.1-alpha.f04ac4ba4.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 +264 -36
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +340 -108
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +268 -36
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +346 -107
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/constants.d.ts +2 -0
- package/dist/src/index.browser.d.ts +2 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/interfaces.d.ts +30 -0
- package/dist/src/manifestUpdater.d.ts +8 -4
- package/dist/src/specFilter.d.ts +2 -1
- package/dist/src/specParser.browser.d.ts +15 -1
- package/dist/src/specParser.d.ts +14 -1
- package/dist/src/utils.d.ts +10 -9
- package/package.json +4 -4
package/dist/index.esm2017.js
CHANGED
|
@@ -23,6 +23,7 @@ var ErrorType;
|
|
|
23
23
|
ErrorType["GenerateAdaptiveCardFailed"] = "generate-adaptive-card-failed";
|
|
24
24
|
ErrorType["GenerateFailed"] = "generate-failed";
|
|
25
25
|
ErrorType["ValidateFailed"] = "validate-failed";
|
|
26
|
+
ErrorType["GetSpecFailed"] = "get-spec-failed";
|
|
26
27
|
ErrorType["Cancelled"] = "cancelled";
|
|
27
28
|
ErrorType["Unknown"] = "unknown";
|
|
28
29
|
})(ErrorType || (ErrorType = {}));
|
|
@@ -45,7 +46,13 @@ var ValidationStatus;
|
|
|
45
46
|
ValidationStatus[ValidationStatus["Valid"] = 0] = "Valid";
|
|
46
47
|
ValidationStatus[ValidationStatus["Warning"] = 1] = "Warning";
|
|
47
48
|
ValidationStatus[ValidationStatus["Error"] = 2] = "Error";
|
|
48
|
-
})(ValidationStatus || (ValidationStatus = {}));
|
|
49
|
+
})(ValidationStatus || (ValidationStatus = {}));
|
|
50
|
+
var ProjectType;
|
|
51
|
+
(function (ProjectType) {
|
|
52
|
+
ProjectType[ProjectType["Copilot"] = 0] = "Copilot";
|
|
53
|
+
ProjectType[ProjectType["SME"] = 1] = "SME";
|
|
54
|
+
ProjectType[ProjectType["TeamsAi"] = 2] = "TeamsAi";
|
|
55
|
+
})(ProjectType || (ProjectType = {}));
|
|
49
56
|
|
|
50
57
|
// Copyright (c) Microsoft Corporation.
|
|
51
58
|
class SpecParserError extends Error {
|
|
@@ -73,6 +80,7 @@ ConstantString.OperationOnlyContainsOptionalParam = "Operation %s contains multi
|
|
|
73
80
|
ConstantString.ConvertSwaggerToOpenAPI = "The Swagger 2.0 file has been converted to OpenAPI 3.0.";
|
|
74
81
|
ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please convert to OpenAPI 3.0 manually before proceeding.";
|
|
75
82
|
ConstantString.MultipleAPIKeyNotSupported = "Multiple API keys are not supported. Please make sure that all selected APIs use the same API key.";
|
|
83
|
+
ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
|
|
76
84
|
ConstantString.WrappedCardVersion = "devPreview";
|
|
77
85
|
ConstantString.WrappedCardSchema = "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.ResponseRenderingTemplate.schema.json";
|
|
78
86
|
ConstantString.WrappedCardResponseLayout = "list";
|
|
@@ -143,11 +151,23 @@ ConstantString.FullDescriptionMaxLens = 4000;
|
|
|
143
151
|
ConstantString.CommandDescriptionMaxLens = 128;
|
|
144
152
|
ConstantString.ParameterDescriptionMaxLens = 128;
|
|
145
153
|
ConstantString.CommandTitleMaxLens = 32;
|
|
146
|
-
ConstantString.ParameterTitleMaxLens = 32;
|
|
154
|
+
ConstantString.ParameterTitleMaxLens = 32;
|
|
155
|
+
ConstantString.SMERequiredParamsMaxNum = 5;
|
|
147
156
|
|
|
148
157
|
// Copyright (c) Microsoft Corporation.
|
|
149
158
|
class Utils {
|
|
150
|
-
static
|
|
159
|
+
static hasNestedObjectInSchema(schema) {
|
|
160
|
+
if (schema.type === "object") {
|
|
161
|
+
for (const property in schema.properties) {
|
|
162
|
+
const nestedSchema = schema.properties[property];
|
|
163
|
+
if (nestedSchema.type === "object") {
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
static checkParameters(paramObject, isCopilot) {
|
|
151
171
|
const paramResult = {
|
|
152
172
|
requiredNum: 0,
|
|
153
173
|
optionalNum: 0,
|
|
@@ -159,7 +179,20 @@ class Utils {
|
|
|
159
179
|
for (let i = 0; i < paramObject.length; i++) {
|
|
160
180
|
const param = paramObject[i];
|
|
161
181
|
const schema = param.schema;
|
|
182
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
183
|
+
paramResult.isValid = false;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
162
186
|
const isRequiredWithoutDefault = param.required && schema.default === undefined;
|
|
187
|
+
if (isCopilot) {
|
|
188
|
+
if (isRequiredWithoutDefault) {
|
|
189
|
+
paramResult.requiredNum = paramResult.requiredNum + 1;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
paramResult.optionalNum = paramResult.optionalNum + 1;
|
|
193
|
+
}
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
163
196
|
if (param.in === "header" || param.in === "cookie") {
|
|
164
197
|
if (isRequiredWithoutDefault) {
|
|
165
198
|
paramResult.isValid = false;
|
|
@@ -186,7 +219,7 @@ class Utils {
|
|
|
186
219
|
}
|
|
187
220
|
return paramResult;
|
|
188
221
|
}
|
|
189
|
-
static checkPostBody(schema, isRequired = false) {
|
|
222
|
+
static checkPostBody(schema, isRequired = false, isCopilot = false) {
|
|
190
223
|
var _a;
|
|
191
224
|
const paramResult = {
|
|
192
225
|
requiredNum: 0,
|
|
@@ -197,6 +230,10 @@ class Utils {
|
|
|
197
230
|
return paramResult;
|
|
198
231
|
}
|
|
199
232
|
const isRequiredWithoutDefault = isRequired && schema.default === undefined;
|
|
233
|
+
if (isCopilot && this.hasNestedObjectInSchema(schema)) {
|
|
234
|
+
paramResult.isValid = false;
|
|
235
|
+
return paramResult;
|
|
236
|
+
}
|
|
200
237
|
if (schema.type === "string" ||
|
|
201
238
|
schema.type === "integer" ||
|
|
202
239
|
schema.type === "boolean" ||
|
|
@@ -215,14 +252,14 @@ class Utils {
|
|
|
215
252
|
if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
|
|
216
253
|
isRequired = true;
|
|
217
254
|
}
|
|
218
|
-
const result = Utils.checkPostBody(properties[property], isRequired);
|
|
255
|
+
const result = Utils.checkPostBody(properties[property], isRequired, isCopilot);
|
|
219
256
|
paramResult.requiredNum += result.requiredNum;
|
|
220
257
|
paramResult.optionalNum += result.optionalNum;
|
|
221
258
|
paramResult.isValid = paramResult.isValid && result.isValid;
|
|
222
259
|
}
|
|
223
260
|
}
|
|
224
261
|
else {
|
|
225
|
-
if (isRequiredWithoutDefault) {
|
|
262
|
+
if (isRequiredWithoutDefault && !isCopilot) {
|
|
226
263
|
paramResult.isValid = false;
|
|
227
264
|
}
|
|
228
265
|
}
|
|
@@ -242,19 +279,19 @@ class Utils {
|
|
|
242
279
|
* 5. response body should be “application/json” and not empty, and response code should be 20X
|
|
243
280
|
* 6. only support request body with “application/json” content type
|
|
244
281
|
*/
|
|
245
|
-
static isSupportedApi(method, path, spec,
|
|
282
|
+
static isSupportedApi(method, path, spec, options) {
|
|
283
|
+
var _a;
|
|
246
284
|
const pathObj = spec.paths[path];
|
|
247
285
|
method = method.toLocaleLowerCase();
|
|
248
286
|
if (pathObj) {
|
|
249
|
-
if ((
|
|
250
|
-
pathObj[method]) {
|
|
287
|
+
if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && pathObj[method]) {
|
|
251
288
|
const securities = pathObj[method].security;
|
|
252
289
|
const authArray = Utils.getAuthArray(securities, spec);
|
|
253
|
-
if (!Utils.isSupportedAuth(authArray,
|
|
290
|
+
if (!Utils.isSupportedAuth(authArray, options)) {
|
|
254
291
|
return false;
|
|
255
292
|
}
|
|
256
293
|
const operationObject = pathObj[method];
|
|
257
|
-
if (!allowMissingId && !operationObject.operationId) {
|
|
294
|
+
if (!options.allowMissingId && !operationObject.operationId) {
|
|
258
295
|
return false;
|
|
259
296
|
}
|
|
260
297
|
const paramObject = operationObject.parameters;
|
|
@@ -273,20 +310,29 @@ class Utils {
|
|
|
273
310
|
optionalNum: 0,
|
|
274
311
|
isValid: true,
|
|
275
312
|
};
|
|
313
|
+
const isCopilot = options.projectType === ProjectType.Copilot;
|
|
276
314
|
if (requestJsonBody) {
|
|
277
315
|
const requestBodySchema = requestJsonBody.schema;
|
|
278
|
-
|
|
316
|
+
if (isCopilot && requestBodySchema.type !== "object") {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
requestBodyParamResult = Utils.checkPostBody(requestBodySchema, requestBody.required, isCopilot);
|
|
279
320
|
}
|
|
280
321
|
if (!requestBodyParamResult.isValid) {
|
|
281
322
|
return false;
|
|
282
323
|
}
|
|
283
|
-
const paramResult = Utils.checkParameters(paramObject);
|
|
324
|
+
const paramResult = Utils.checkParameters(paramObject, isCopilot);
|
|
284
325
|
if (!paramResult.isValid) {
|
|
285
326
|
return false;
|
|
286
327
|
}
|
|
328
|
+
// Copilot support arbitrary parameters
|
|
329
|
+
if (isCopilot) {
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
287
332
|
if (requestBodyParamResult.requiredNum + paramResult.requiredNum > 1) {
|
|
288
|
-
if (allowMultipleParameters &&
|
|
289
|
-
requestBodyParamResult.requiredNum + paramResult.requiredNum <=
|
|
333
|
+
if (options.allowMultipleParameters &&
|
|
334
|
+
requestBodyParamResult.requiredNum + paramResult.requiredNum <=
|
|
335
|
+
ConstantString.SMERequiredParamsMaxNum) {
|
|
290
336
|
return true;
|
|
291
337
|
}
|
|
292
338
|
return false;
|
|
@@ -305,27 +351,29 @@ class Utils {
|
|
|
305
351
|
}
|
|
306
352
|
return false;
|
|
307
353
|
}
|
|
308
|
-
static isSupportedAuth(authSchemaArray,
|
|
354
|
+
static isSupportedAuth(authSchemaArray, options) {
|
|
309
355
|
if (authSchemaArray.length === 0) {
|
|
310
356
|
return true;
|
|
311
357
|
}
|
|
312
|
-
if (allowAPIKeyAuth || allowOauth2) {
|
|
358
|
+
if (options.allowAPIKeyAuth || options.allowOauth2) {
|
|
313
359
|
// Currently we don't support multiple auth in one operation
|
|
314
360
|
if (authSchemaArray.length > 0 && authSchemaArray.every((auths) => auths.length > 1)) {
|
|
315
361
|
return false;
|
|
316
362
|
}
|
|
317
363
|
for (const auths of authSchemaArray) {
|
|
318
364
|
if (auths.length === 1) {
|
|
319
|
-
if (!allowOauth2 &&
|
|
365
|
+
if (!options.allowOauth2 &&
|
|
366
|
+
options.allowAPIKeyAuth &&
|
|
367
|
+
Utils.isAPIKeyAuth(auths[0].authSchema)) {
|
|
320
368
|
return true;
|
|
321
369
|
}
|
|
322
|
-
else if (!allowAPIKeyAuth &&
|
|
323
|
-
allowOauth2 &&
|
|
370
|
+
else if (!options.allowAPIKeyAuth &&
|
|
371
|
+
options.allowOauth2 &&
|
|
324
372
|
Utils.isBearerTokenAuth(auths[0].authSchema)) {
|
|
325
373
|
return true;
|
|
326
374
|
}
|
|
327
|
-
else if (allowAPIKeyAuth &&
|
|
328
|
-
allowOauth2 &&
|
|
375
|
+
else if (options.allowAPIKeyAuth &&
|
|
376
|
+
options.allowOauth2 &&
|
|
329
377
|
(Utils.isAPIKeyAuth(auths[0].authSchema) ||
|
|
330
378
|
Utils.isBearerTokenAuth(auths[0].authSchema))) {
|
|
331
379
|
return true;
|
|
@@ -454,7 +502,7 @@ class Utils {
|
|
|
454
502
|
}
|
|
455
503
|
return errors;
|
|
456
504
|
}
|
|
457
|
-
static validateServer(spec,
|
|
505
|
+
static validateServer(spec, options) {
|
|
458
506
|
const errors = [];
|
|
459
507
|
let hasTopLevelServers = false;
|
|
460
508
|
let hasPathLevelServers = false;
|
|
@@ -475,7 +523,7 @@ class Utils {
|
|
|
475
523
|
}
|
|
476
524
|
for (const method in methods) {
|
|
477
525
|
const operationObject = methods[method];
|
|
478
|
-
if (Utils.isSupportedApi(method, path, spec,
|
|
526
|
+
if (Utils.isSupportedApi(method, path, spec, options)) {
|
|
479
527
|
if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
|
|
480
528
|
hasOperationLevelServers = true;
|
|
481
529
|
const serverErrors = Utils.checkServerUrl(operationObject.servers);
|
|
@@ -562,7 +610,7 @@ class Utils {
|
|
|
562
610
|
param.value = schema.default;
|
|
563
611
|
}
|
|
564
612
|
}
|
|
565
|
-
static parseApiInfo(operationItem,
|
|
613
|
+
static parseApiInfo(operationItem, options) {
|
|
566
614
|
var _a, _b;
|
|
567
615
|
const requiredParams = [];
|
|
568
616
|
const optionalParams = [];
|
|
@@ -576,7 +624,7 @@ class Utils {
|
|
|
576
624
|
description: ((_a = param.description) !== null && _a !== void 0 ? _a : "").slice(0, ConstantString.ParameterDescriptionMaxLens),
|
|
577
625
|
};
|
|
578
626
|
const schema = param.schema;
|
|
579
|
-
if (allowMultipleParameters && schema) {
|
|
627
|
+
if (options.allowMultipleParameters && schema) {
|
|
580
628
|
Utils.updateParameterWithInputType(schema, parameter);
|
|
581
629
|
}
|
|
582
630
|
if (param.in !== "header" && param.in !== "cookie") {
|
|
@@ -594,7 +642,7 @@ class Utils {
|
|
|
594
642
|
const requestJson = requestBody.content["application/json"];
|
|
595
643
|
if (Object.keys(requestJson).length !== 0) {
|
|
596
644
|
const schema = requestJson.schema;
|
|
597
|
-
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", allowMultipleParameters, requestBody.required);
|
|
645
|
+
const [requiredP, optionalP] = Utils.generateParametersFromSchema(schema, "requestBody", !!options.allowMultipleParameters, requestBody.required);
|
|
598
646
|
requiredParams.push(...requiredP);
|
|
599
647
|
optionalParams.push(...optionalP);
|
|
600
648
|
}
|
|
@@ -625,14 +673,14 @@ class Utils {
|
|
|
625
673
|
}
|
|
626
674
|
return [command, warning];
|
|
627
675
|
}
|
|
628
|
-
static listSupportedAPIs(spec,
|
|
676
|
+
static listSupportedAPIs(spec, options) {
|
|
629
677
|
const paths = spec.paths;
|
|
630
678
|
const result = {};
|
|
631
679
|
for (const path in paths) {
|
|
632
680
|
const methods = paths[path];
|
|
633
681
|
for (const method in methods) {
|
|
634
682
|
// For developer preview, only support GET operation with only 1 parameter without auth
|
|
635
|
-
if (Utils.isSupportedApi(method, path, spec,
|
|
683
|
+
if (Utils.isSupportedApi(method, path, spec, options)) {
|
|
636
684
|
const operationObject = methods[method];
|
|
637
685
|
result[`${method.toUpperCase()} ${path}`] = operationObject;
|
|
638
686
|
}
|
|
@@ -640,7 +688,7 @@ class Utils {
|
|
|
640
688
|
}
|
|
641
689
|
return result;
|
|
642
690
|
}
|
|
643
|
-
static validateSpec(spec, parser, isSwaggerFile,
|
|
691
|
+
static validateSpec(spec, parser, isSwaggerFile, options) {
|
|
644
692
|
const errors = [];
|
|
645
693
|
const warnings = [];
|
|
646
694
|
if (isSwaggerFile) {
|
|
@@ -650,7 +698,7 @@ class Utils {
|
|
|
650
698
|
});
|
|
651
699
|
}
|
|
652
700
|
// Server validation
|
|
653
|
-
const serverErrors = Utils.validateServer(spec,
|
|
701
|
+
const serverErrors = Utils.validateServer(spec, options);
|
|
654
702
|
errors.push(...serverErrors);
|
|
655
703
|
// Remote reference not supported
|
|
656
704
|
const refPaths = parser.$refs.paths();
|
|
@@ -663,7 +711,7 @@ class Utils {
|
|
|
663
711
|
});
|
|
664
712
|
}
|
|
665
713
|
// No supported API
|
|
666
|
-
const apiMap = Utils.listSupportedAPIs(spec,
|
|
714
|
+
const apiMap = Utils.listSupportedAPIs(spec, options);
|
|
667
715
|
if (Object.keys(apiMap).length === 0) {
|
|
668
716
|
errors.push({
|
|
669
717
|
type: ErrorType.NoSupportedApi,
|
|
@@ -734,6 +782,8 @@ class SpecParser {
|
|
|
734
782
|
allowAPIKeyAuth: false,
|
|
735
783
|
allowMultipleParameters: false,
|
|
736
784
|
allowOauth2: false,
|
|
785
|
+
allowMethods: ["get", "post"],
|
|
786
|
+
projectType: ProjectType.SME,
|
|
737
787
|
};
|
|
738
788
|
this.pathOrSpec = pathOrDoc;
|
|
739
789
|
this.parser = new SwaggerParser();
|
|
@@ -770,7 +820,7 @@ class SpecParser {
|
|
|
770
820
|
],
|
|
771
821
|
};
|
|
772
822
|
}
|
|
773
|
-
return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options
|
|
823
|
+
return Utils.validateSpec(this.spec, this.parser, !!this.isSwaggerFile, this.options);
|
|
774
824
|
}
|
|
775
825
|
catch (err) {
|
|
776
826
|
throw new SpecParserError(err.toString(), ErrorType.ValidateFailed);
|
|
@@ -789,7 +839,7 @@ class SpecParser {
|
|
|
789
839
|
if (!operationId) {
|
|
790
840
|
continue;
|
|
791
841
|
}
|
|
792
|
-
const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options
|
|
842
|
+
const [command, warning] = Utils.parseApiInfo(pathObjectItem, this.options);
|
|
793
843
|
const apiInfo = {
|
|
794
844
|
method: method,
|
|
795
845
|
path: path,
|
|
@@ -818,12 +868,32 @@ class SpecParser {
|
|
|
818
868
|
async list() {
|
|
819
869
|
throw new Error("Method not implemented.");
|
|
820
870
|
}
|
|
871
|
+
/**
|
|
872
|
+
* Generate specs according to the filters.
|
|
873
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
874
|
+
*/
|
|
875
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
876
|
+
async getFilteredSpecs(filter, signal) {
|
|
877
|
+
throw new Error("Method not implemented.");
|
|
878
|
+
}
|
|
879
|
+
/**
|
|
880
|
+
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
881
|
+
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
882
|
+
* @param filter An array of strings that represent the filters to apply when generating the artifacts. If filter is empty, it would process nothing.
|
|
883
|
+
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
884
|
+
* @param pluginFilePath File path of the api plugin file to generate.
|
|
885
|
+
*/
|
|
886
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
887
|
+
async generateForCopilot(manifestPath, filter, outputSpecPath, pluginFilePath, signal) {
|
|
888
|
+
throw new Error("Method not implemented.");
|
|
889
|
+
}
|
|
821
890
|
/**
|
|
822
891
|
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
823
892
|
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
824
893
|
* @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
894
|
* @param outputSpecPath File path of the new OpenAPI specification file to generate. If not specified or empty, no spec file will be generated.
|
|
826
895
|
* @param adaptiveCardFolder Folder path where the Adaptive Card files will be generated. If not specified or empty, Adaptive Card files will not be generated.
|
|
896
|
+
* @param isMe Boolean that indicates whether the project is an Messaging Extension. For Messaging Extension, composeExtensions will be added in Teams app manifest.
|
|
827
897
|
*/
|
|
828
898
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
829
899
|
async generate(manifestPath, filter, outputSpecPath, adaptiveCardFolder, signal) {
|
|
@@ -843,11 +913,169 @@ class SpecParser {
|
|
|
843
913
|
if (this.apiMap !== undefined) {
|
|
844
914
|
return this.apiMap;
|
|
845
915
|
}
|
|
846
|
-
const result = Utils.listSupportedAPIs(spec, this.options
|
|
916
|
+
const result = Utils.listSupportedAPIs(spec, this.options);
|
|
847
917
|
this.apiMap = result;
|
|
848
918
|
return result;
|
|
849
919
|
}
|
|
850
920
|
}
|
|
851
921
|
|
|
852
|
-
|
|
922
|
+
// Copyright (c) Microsoft Corporation.
|
|
923
|
+
class AdaptiveCardGenerator {
|
|
924
|
+
static generateAdaptiveCard(operationItem) {
|
|
925
|
+
try {
|
|
926
|
+
const json = Utils.getResponseJson(operationItem);
|
|
927
|
+
let cardBody = [];
|
|
928
|
+
let schema = json.schema;
|
|
929
|
+
let jsonPath = "$";
|
|
930
|
+
if (schema && Object.keys(schema).length > 0) {
|
|
931
|
+
jsonPath = AdaptiveCardGenerator.getResponseJsonPathFromSchema(schema);
|
|
932
|
+
if (jsonPath !== "$") {
|
|
933
|
+
schema = schema.properties[jsonPath];
|
|
934
|
+
}
|
|
935
|
+
cardBody = AdaptiveCardGenerator.generateCardFromResponse(schema, "");
|
|
936
|
+
}
|
|
937
|
+
// if no schema, try to use example value
|
|
938
|
+
if (cardBody.length === 0 && (json.examples || json.example)) {
|
|
939
|
+
cardBody = [
|
|
940
|
+
{
|
|
941
|
+
type: ConstantString.TextBlockType,
|
|
942
|
+
text: "${jsonStringify($root)}",
|
|
943
|
+
wrap: true,
|
|
944
|
+
},
|
|
945
|
+
];
|
|
946
|
+
}
|
|
947
|
+
// if no example value, use default success response
|
|
948
|
+
if (cardBody.length === 0) {
|
|
949
|
+
cardBody = [
|
|
950
|
+
{
|
|
951
|
+
type: ConstantString.TextBlockType,
|
|
952
|
+
text: "success",
|
|
953
|
+
wrap: true,
|
|
954
|
+
},
|
|
955
|
+
];
|
|
956
|
+
}
|
|
957
|
+
const fullCard = {
|
|
958
|
+
type: ConstantString.AdaptiveCardType,
|
|
959
|
+
$schema: ConstantString.AdaptiveCardSchema,
|
|
960
|
+
version: ConstantString.AdaptiveCardVersion,
|
|
961
|
+
body: cardBody,
|
|
962
|
+
};
|
|
963
|
+
return [fullCard, jsonPath];
|
|
964
|
+
}
|
|
965
|
+
catch (err) {
|
|
966
|
+
throw new SpecParserError(err.toString(), ErrorType.GenerateAdaptiveCardFailed);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
static generateCardFromResponse(schema, name, parentArrayName = "") {
|
|
970
|
+
if (schema.type === "array") {
|
|
971
|
+
// schema.items can be arbitrary object: schema { type: array, items: {} }
|
|
972
|
+
if (Object.keys(schema.items).length === 0) {
|
|
973
|
+
return [
|
|
974
|
+
{
|
|
975
|
+
type: ConstantString.TextBlockType,
|
|
976
|
+
text: name ? `${name}: \${jsonStringify(${name})}` : "result: ${jsonStringify($root)}",
|
|
977
|
+
wrap: true,
|
|
978
|
+
},
|
|
979
|
+
];
|
|
980
|
+
}
|
|
981
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(schema.items, "", name);
|
|
982
|
+
const template = {
|
|
983
|
+
type: ConstantString.ContainerType,
|
|
984
|
+
$data: name ? `\${${name}}` : "${$root}",
|
|
985
|
+
items: Array(),
|
|
986
|
+
};
|
|
987
|
+
template.items.push(...obj);
|
|
988
|
+
return [template];
|
|
989
|
+
}
|
|
990
|
+
// some schema may not contain type but contain properties
|
|
991
|
+
if (schema.type === "object" || (!schema.type && schema.properties)) {
|
|
992
|
+
const { properties } = schema;
|
|
993
|
+
const result = [];
|
|
994
|
+
for (const property in properties) {
|
|
995
|
+
const obj = AdaptiveCardGenerator.generateCardFromResponse(properties[property], name ? `${name}.${property}` : property, parentArrayName);
|
|
996
|
+
result.push(...obj);
|
|
997
|
+
}
|
|
998
|
+
if (schema.additionalProperties) {
|
|
999
|
+
// TODO: better ways to handler warnings.
|
|
1000
|
+
console.warn(ConstantString.AdditionalPropertiesNotSupported);
|
|
1001
|
+
}
|
|
1002
|
+
return result;
|
|
1003
|
+
}
|
|
1004
|
+
if (schema.type === "string" ||
|
|
1005
|
+
schema.type === "integer" ||
|
|
1006
|
+
schema.type === "boolean" ||
|
|
1007
|
+
schema.type === "number") {
|
|
1008
|
+
if (!AdaptiveCardGenerator.isImageUrlProperty(schema, name, parentArrayName)) {
|
|
1009
|
+
// string in root: "ddd"
|
|
1010
|
+
let text = "result: ${$root}";
|
|
1011
|
+
if (name) {
|
|
1012
|
+
// object { id: "1" }
|
|
1013
|
+
text = `${name}: \${if(${name}, ${name}, 'N/A')}`;
|
|
1014
|
+
if (parentArrayName) {
|
|
1015
|
+
// object types inside array: { tags: ["id": 1, "name": "name"] }
|
|
1016
|
+
text = `${parentArrayName}.${text}`;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
else if (parentArrayName) {
|
|
1020
|
+
// string array: photoUrls: ["1", "2"]
|
|
1021
|
+
text = `${parentArrayName}: ` + "${$data}";
|
|
1022
|
+
}
|
|
1023
|
+
return [
|
|
1024
|
+
{
|
|
1025
|
+
type: ConstantString.TextBlockType,
|
|
1026
|
+
text,
|
|
1027
|
+
wrap: true,
|
|
1028
|
+
},
|
|
1029
|
+
];
|
|
1030
|
+
}
|
|
1031
|
+
else {
|
|
1032
|
+
if (name) {
|
|
1033
|
+
return [
|
|
1034
|
+
{
|
|
1035
|
+
type: "Image",
|
|
1036
|
+
url: `\${${name}}`,
|
|
1037
|
+
$when: `\${${name} != null}`,
|
|
1038
|
+
},
|
|
1039
|
+
];
|
|
1040
|
+
}
|
|
1041
|
+
else {
|
|
1042
|
+
return [
|
|
1043
|
+
{
|
|
1044
|
+
type: "Image",
|
|
1045
|
+
url: "${$data}",
|
|
1046
|
+
$when: "${$data != null}",
|
|
1047
|
+
},
|
|
1048
|
+
];
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
if (schema.oneOf || schema.anyOf || schema.not || schema.allOf) {
|
|
1053
|
+
throw new Error(Utils.format(ConstantString.SchemaNotSupported, JSON.stringify(schema)));
|
|
1054
|
+
}
|
|
1055
|
+
throw new Error(Utils.format(ConstantString.UnknownSchema, JSON.stringify(schema)));
|
|
1056
|
+
}
|
|
1057
|
+
// Find the first array property in the response schema object with the well-known name
|
|
1058
|
+
static getResponseJsonPathFromSchema(schema) {
|
|
1059
|
+
if (schema.type === "object" || (!schema.type && schema.properties)) {
|
|
1060
|
+
const { properties } = schema;
|
|
1061
|
+
for (const property in properties) {
|
|
1062
|
+
const schema = properties[property];
|
|
1063
|
+
if (schema.type === "array" &&
|
|
1064
|
+
Utils.isWellKnownName(property, ConstantString.WellknownResultNames)) {
|
|
1065
|
+
return property;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
return "$";
|
|
1070
|
+
}
|
|
1071
|
+
static isImageUrlProperty(schema, name, parentArrayName) {
|
|
1072
|
+
const propertyName = name ? name : parentArrayName;
|
|
1073
|
+
return (!!propertyName &&
|
|
1074
|
+
schema.type === "string" &&
|
|
1075
|
+
Utils.isWellKnownName(propertyName, ConstantString.WellknownImageName) &&
|
|
1076
|
+
(propertyName.toLocaleLowerCase().indexOf("url") >= 0 || schema.format === "uri"));
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
export { AdaptiveCardGenerator, ConstantString, ErrorType, SpecParser, SpecParserError, Utils, ValidationStatus, WarningType };
|
|
853
1081
|
//# sourceMappingURL=index.esm2017.js.map
|