@midwayjs/swagger 4.0.0-beta.12 → 4.0.0-beta.14
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.
|
@@ -381,6 +381,12 @@ export interface SwaggerOptions {
|
|
|
381
381
|
* Weather to generate the Tag for controller
|
|
382
382
|
*/
|
|
383
383
|
isGenerateTagForController?: boolean;
|
|
384
|
+
/**
|
|
385
|
+
* Enable inferring schema metadata from @midwayjs/validation DTO rules.
|
|
386
|
+
* When enabled, inferred metadata only fills fields that are not explicitly
|
|
387
|
+
* defined by @ApiProperty.
|
|
388
|
+
*/
|
|
389
|
+
useValidationSchema?: boolean;
|
|
384
390
|
}
|
|
385
391
|
export interface MixDecoratorMetadata {
|
|
386
392
|
key: string;
|
|
@@ -52,6 +52,11 @@ export declare class SwaggerExplorer {
|
|
|
52
52
|
* @param clzz
|
|
53
53
|
*/
|
|
54
54
|
protected parseClzz(clzz: Type): any;
|
|
55
|
+
private mergePropertyMetadata;
|
|
56
|
+
protected getValidationSchemaHelper(): any;
|
|
57
|
+
private inferValidationProperties;
|
|
58
|
+
private inferValidateProperties;
|
|
59
|
+
protected hasClassValidatorMetadata(clzz: Type): boolean;
|
|
55
60
|
/**
|
|
56
61
|
* 授权验证
|
|
57
62
|
* @param opts
|
package/dist/swaggerExplorer.js
CHANGED
|
@@ -15,6 +15,8 @@ const constants_1 = require("./constants");
|
|
|
15
15
|
const documentBuilder_1 = require("./documentBuilder");
|
|
16
16
|
const _1 = require(".");
|
|
17
17
|
const enum_utils_1 = require("./common/enum.utils");
|
|
18
|
+
const VALIDATION_RULES_KEY = 'validation:rules';
|
|
19
|
+
const VALIDATE_RULES_KEY = 'common:rules';
|
|
18
20
|
let SwaggerExplorer = class SwaggerExplorer {
|
|
19
21
|
swaggerConfig = {};
|
|
20
22
|
documentBuilder = new documentBuilder_1.DocumentBuilder();
|
|
@@ -774,6 +776,18 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
774
776
|
for (const key in props) {
|
|
775
777
|
props[key] = props[key][props[key].length - 1];
|
|
776
778
|
}
|
|
779
|
+
if (this.swaggerConfig?.useValidationSchema) {
|
|
780
|
+
const inferredProps = this.inferValidationProperties(clzz);
|
|
781
|
+
for (const key of Object.keys(inferredProps)) {
|
|
782
|
+
if (!props[key]) {
|
|
783
|
+
props[key] = inferredProps[key];
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
const existingMeta = props[key].metadata || {};
|
|
787
|
+
const inferredMeta = inferredProps[key].metadata || {};
|
|
788
|
+
props[key].metadata = this.mergePropertyMetadata(existingMeta, inferredMeta);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
777
791
|
const tt = {
|
|
778
792
|
type: 'object',
|
|
779
793
|
properties: {},
|
|
@@ -845,6 +859,120 @@ let SwaggerExplorer = class SwaggerExplorer {
|
|
|
845
859
|
// just for test
|
|
846
860
|
return tt;
|
|
847
861
|
}
|
|
862
|
+
mergePropertyMetadata(swaggerMetadata, inferredMetadata) {
|
|
863
|
+
const mergedMetadata = { ...swaggerMetadata };
|
|
864
|
+
const fillableKeys = [
|
|
865
|
+
'type',
|
|
866
|
+
'items',
|
|
867
|
+
'format',
|
|
868
|
+
'enum',
|
|
869
|
+
'$ref',
|
|
870
|
+
'pattern',
|
|
871
|
+
'default',
|
|
872
|
+
];
|
|
873
|
+
for (const key of fillableKeys) {
|
|
874
|
+
if (mergedMetadata[key] === undefined &&
|
|
875
|
+
inferredMetadata[key] !== undefined) {
|
|
876
|
+
mergedMetadata[key] = inferredMetadata[key];
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
if (mergedMetadata.required === undefined &&
|
|
880
|
+
inferredMetadata.required !== undefined) {
|
|
881
|
+
mergedMetadata.required = inferredMetadata.required;
|
|
882
|
+
}
|
|
883
|
+
return mergedMetadata;
|
|
884
|
+
}
|
|
885
|
+
getValidationSchemaHelper() {
|
|
886
|
+
try {
|
|
887
|
+
const validationPkg = (0, core_1.safeRequire)('@midwayjs/validation');
|
|
888
|
+
const registry = validationPkg?.registry;
|
|
889
|
+
if (!registry?.getDefaultValidator) {
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
return registry.getDefaultValidator()?.schemaHelper;
|
|
893
|
+
}
|
|
894
|
+
catch {
|
|
895
|
+
// When @midwayjs/validate and @midwayjs/validation are both installed in
|
|
896
|
+
// the same process, loading validation package may throw duplicated error
|
|
897
|
+
// group exceptions. Swagger should degrade gracefully in this case.
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
inferValidationProperties(clzz) {
|
|
902
|
+
const ruleProps = core_1.MetadataManager.getPropertiesWithMetadata(VALIDATION_RULES_KEY, clzz) ||
|
|
903
|
+
{};
|
|
904
|
+
const hasRuleMetadata = Object.keys(ruleProps).length > 0;
|
|
905
|
+
const validateRuleProps = core_1.MetadataManager.getPropertiesWithMetadata(VALIDATE_RULES_KEY, clzz) || {};
|
|
906
|
+
const hasValidateRuleMetadata = Object.keys(validateRuleProps).length > 0;
|
|
907
|
+
const hasClassValidatorMetadata = this.hasClassValidatorMetadata(clzz);
|
|
908
|
+
if (!hasRuleMetadata &&
|
|
909
|
+
!hasClassValidatorMetadata &&
|
|
910
|
+
!hasValidateRuleMetadata) {
|
|
911
|
+
return {};
|
|
912
|
+
}
|
|
913
|
+
const inferredProps = {};
|
|
914
|
+
if (hasRuleMetadata || hasClassValidatorMetadata) {
|
|
915
|
+
const schemaHelper = this.getValidationSchemaHelper();
|
|
916
|
+
if (schemaHelper &&
|
|
917
|
+
typeof schemaHelper.getSwaggerPropertyKeys === 'function' &&
|
|
918
|
+
typeof schemaHelper.getSwaggerPropertyMetadata === 'function') {
|
|
919
|
+
const propertyKeys = schemaHelper.getSwaggerPropertyKeys(clzz) || [];
|
|
920
|
+
for (const key of propertyKeys) {
|
|
921
|
+
const metadata = schemaHelper.getSwaggerPropertyMetadata(clzz, key);
|
|
922
|
+
if (metadata) {
|
|
923
|
+
inferredProps[key] = {
|
|
924
|
+
metadata,
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
if (hasValidateRuleMetadata) {
|
|
931
|
+
const validateInferredProps = this.inferValidateProperties(clzz);
|
|
932
|
+
for (const [key, value] of Object.entries(validateInferredProps)) {
|
|
933
|
+
if (!inferredProps[key]) {
|
|
934
|
+
inferredProps[key] = value;
|
|
935
|
+
continue;
|
|
936
|
+
}
|
|
937
|
+
const mergedMetadata = this.mergePropertyMetadata(inferredProps[key].metadata || {}, value.metadata || {});
|
|
938
|
+
inferredProps[key] = {
|
|
939
|
+
metadata: mergedMetadata,
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
return inferredProps;
|
|
944
|
+
}
|
|
945
|
+
inferValidateProperties(clzz) {
|
|
946
|
+
const inferredProps = {};
|
|
947
|
+
const ruleProps = core_1.MetadataManager.getPropertiesWithMetadata(VALIDATE_RULES_KEY, clzz) || {};
|
|
948
|
+
for (const key of Object.keys(ruleProps)) {
|
|
949
|
+
let schema = ruleProps[key];
|
|
950
|
+
if (typeof schema === 'function') {
|
|
951
|
+
schema = schema();
|
|
952
|
+
}
|
|
953
|
+
const metadata = inferJoiPropertyMetadata(schema);
|
|
954
|
+
if (metadata) {
|
|
955
|
+
inferredProps[key] = {
|
|
956
|
+
metadata,
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
return inferredProps;
|
|
961
|
+
}
|
|
962
|
+
hasClassValidatorMetadata(clzz) {
|
|
963
|
+
try {
|
|
964
|
+
const classValidator = (0, core_1.safeRequire)('class-validator-multi-lang-lite');
|
|
965
|
+
const storage = classValidator?.getMetadataStorage?.();
|
|
966
|
+
if (!storage?.getTargetValidationMetadatas) {
|
|
967
|
+
return false;
|
|
968
|
+
}
|
|
969
|
+
const metadatas = storage.getTargetValidationMetadatas(clzz, '', false, false) || [];
|
|
970
|
+
return metadatas.length > 0;
|
|
971
|
+
}
|
|
972
|
+
catch {
|
|
973
|
+
return false;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
848
976
|
/**
|
|
849
977
|
* 授权验证
|
|
850
978
|
* @param opts
|
|
@@ -962,6 +1090,47 @@ function convertSchemaType(value) {
|
|
|
962
1090
|
return 'object';
|
|
963
1091
|
}
|
|
964
1092
|
}
|
|
1093
|
+
function inferJoiPropertyMetadata(schema) {
|
|
1094
|
+
if (!schema || typeof schema.describe !== 'function') {
|
|
1095
|
+
return null;
|
|
1096
|
+
}
|
|
1097
|
+
const desc = schema.describe();
|
|
1098
|
+
if (!desc || typeof desc !== 'object') {
|
|
1099
|
+
return null;
|
|
1100
|
+
}
|
|
1101
|
+
const typeMap = {
|
|
1102
|
+
string: 'string',
|
|
1103
|
+
number: 'number',
|
|
1104
|
+
boolean: 'boolean',
|
|
1105
|
+
array: 'array',
|
|
1106
|
+
date: 'string',
|
|
1107
|
+
object: 'object',
|
|
1108
|
+
};
|
|
1109
|
+
const metadata = {
|
|
1110
|
+
type: typeMap[desc.type] || 'object',
|
|
1111
|
+
};
|
|
1112
|
+
if (desc?.flags?.presence === 'required') {
|
|
1113
|
+
metadata.required = true;
|
|
1114
|
+
}
|
|
1115
|
+
else if (desc?.flags?.presence === 'optional' || !desc?.flags?.presence) {
|
|
1116
|
+
metadata.required = false;
|
|
1117
|
+
}
|
|
1118
|
+
if (desc.type === 'array' && Array.isArray(desc.items)) {
|
|
1119
|
+
metadata.items = {
|
|
1120
|
+
type: typeMap[desc.items[0]?.type] || 'object',
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
if (desc.type === 'date') {
|
|
1124
|
+
metadata.format = 'date-time';
|
|
1125
|
+
}
|
|
1126
|
+
if (Array.isArray(desc.allow)) {
|
|
1127
|
+
const enumValues = desc.allow.filter(item => item !== '' && item !== null && item !== undefined);
|
|
1128
|
+
if (enumValues.length > 0) {
|
|
1129
|
+
metadata.enum = enumValues;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
return metadata;
|
|
1133
|
+
}
|
|
965
1134
|
function getNotEmptyValue(...args) {
|
|
966
1135
|
for (const arg of args) {
|
|
967
1136
|
if (arg) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midwayjs/swagger",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.14",
|
|
4
4
|
"description": "Midway Component for Swagger API Documentation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
],
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@apidevtools/swagger-parser": "11.0.1",
|
|
15
|
-
"@midwayjs/core": "^4.0.0-beta.
|
|
16
|
-
"@midwayjs/koa": "^4.0.0-beta.
|
|
17
|
-
"@midwayjs/mock": "^4.0.0-beta.
|
|
18
|
-
"@midwayjs/validate": "^4.0.0-beta.
|
|
15
|
+
"@midwayjs/core": "^4.0.0-beta.14",
|
|
16
|
+
"@midwayjs/koa": "^4.0.0-beta.14",
|
|
17
|
+
"@midwayjs/mock": "^4.0.0-beta.14",
|
|
18
|
+
"@midwayjs/validate": "^4.0.0-beta.14",
|
|
19
19
|
"swagger-ui-dist": "5.18.3"
|
|
20
20
|
},
|
|
21
21
|
"author": "Kurten Chan <chinkurten@gmail.com>",
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
"type": "git",
|
|
31
31
|
"url": "https://github.com/midwayjs/midway.git"
|
|
32
32
|
},
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "52335cb1baa00754fffd48487f6153a3b2f1f50a"
|
|
34
34
|
}
|