This commit is contained in:
Phoenix He 2020-12-01 08:39:51 +08:00
Родитель 341a305ee7
Коммит 6122fab5a0
11 изменённых файлов: 101 добавлений и 52 удалений

Просмотреть файл

@ -92,14 +92,18 @@ export class LiveValidatorLoader implements Loader<SwaggerSpec> {
);
private constructor(private opts: LiveValidatorLoaderOptions) {
setDefaultOpts(opts, {
transformToNewSchemaFormat: false,
transformToNewSchemaFormat: true,
loadSuppression: Object.keys(allErrorConstants),
});
this.jsonLoader = JsonLoader.create(opts);
this.swaggerLoader = SwaggerLoader.create(opts);
this.schemaValidator = new AjvSchemaValidator(this.jsonLoader);
this.schemaValidator = new AjvSchemaValidator(this.jsonLoader, {
strictTypes: false,
strict: false,
strictTuples: false
});
this.transformContext = getTransformContext(this.jsonLoader, this.schemaValidator, [
xmsPathsTransformer,
@ -168,8 +172,7 @@ export class LiveValidatorLoader implements Loader<SwaggerSpec> {
if (param.required) {
copyInfo(param, schema);
this.addRequiredToSchema(schema, "body");
}
else {
} else {
operation._bodyTransform = bodyTransformIfNotRequiredAndEmpty;
}
break;
@ -272,11 +275,10 @@ const parameterTransform = {
const bodyTransformIfNotRequiredAndEmpty = (body: any) => {
if (body && Object.keys(body).length === 0 && body.constructor === Object) {
return undefined;
}
else {
} else {
return body;
}
}
};
const addParamTransform = (it: Operation | Response, param: Parameter) => {
const transform = parameterTransform[param.type! as keyof typeof parameterTransform];

Просмотреть файл

@ -79,8 +79,10 @@ export class RequestResponse {
}
export const requestResponseDefinition: Schema = {
type: "object",
properties: {
liveRequest: {
type: "object",
required: ["url", "method"],
properties: {
headers: {
@ -90,6 +92,7 @@ export const requestResponseDefinition: Schema = {
},
},
query: {
type: "object",
nullable: true,
additionalProperties: {
oneOf: [
@ -112,23 +115,45 @@ export const requestResponseDefinition: Schema = {
type: "string",
},
body: {
nullable: true,
oneOf: [
{
type: "object",
},
{
type: "array",
},
{
type: "null",
},
],
},
},
},
liveResponse: {
type: "object",
required: ["statusCode"],
properties: {
statusCode: {
type: "string",
},
headers: {
type: "object",
additionalProperties: {
type: "string",
},
},
body: {
nullable: true,
oneOf: [
{
type: "object",
},
{
type: "array",
},
{
type: "null",
},
],
},
},
},

Просмотреть файл

@ -21,7 +21,7 @@ interface FileCache {
mockName: string;
}
export const $id = "id";
export const $id = "$id";
export class JsonLoader implements Loader<Json> {
private fileLoader: FileLoader;

Просмотреть файл

@ -195,13 +195,13 @@ interface BaseSchema {
modelAsString?: boolean;
values?: Array<{ value: any; description?: string; name?: string }>;
};
type?: string;
type?: string | string[];
items?: Schema | Schema[];
}
export type SchemaType = "object" | "array" | "string" | "integer" | "number" | "boolean" | "null";
export interface Schema extends BaseSchema {
type?: SchemaType;
type?: SchemaType | SchemaType[];
allOf?: Schema[];
anyOf?: Schema[];
oneOf?: Schema[];

Просмотреть файл

@ -1,4 +1,5 @@
import { CodeGen, default as Ajv, Format, _ } from "ajv";
import { default as Ajv, Format, _ } from "ajv";
import { default as addAjvFormats } from "ajv-formats";
import { JsonLoader } from "../swagger/jsonLoader";
import { Schema } from "../swagger/swaggerTypes";
import { xmsMutability, xmsSecret } from "../util/constants";
@ -18,7 +19,7 @@ export const ajvEnableReadOnlyAndXmsMutability = (ajv: Ajv) => {
const eq = _`===`;
cxt.pass(_`this.isResponse || ${cxt.data} ${eq} null || ${cxt.data} ${eq} undefined`);
}
}
},
});
ajv.addKeyword({
@ -35,18 +36,22 @@ export const ajvEnableReadOnlyAndXmsMutability = (ajv: Ajv) => {
throw new Error(`Invalid ${xmsMutability} value: ${JSON.stringify(mutability)}`);
}
const eq = _`===`;
cxt.pass(_`${validInRequest ? "!" : ""}this.isResponse || ${cxt.data} ${eq} null || ${cxt.data} ${eq} undefined`);
const cond = validInRequest ? _`!this.isResponse` : _`this.isResponse`;
cxt.pass(_`${cond} || ${cxt.data} ${eq} null || ${cxt.data} ${eq} undefined`);
},
});
};
export const ajvEnableXmsSecret = (ajv: Ajv) => {
ajv.addKeyword({
keyword: xmsSecret
keyword: xmsSecret,
metaSchema: { type: "boolean" } as Schema,
inline: (it: CompilationContext, _keyword: string, isSecret: boolean) => {
const data = `data${it.dataLevel || ""}`;
return isSecret ? `!this.isResponse || ${data} === null || ${data} === undefined` : "1";
code: (ctx) => {
const isSecret = ctx.schema;
if (isSecret) {
const eq = _`===`;
ctx.pass(_`!this.isResponse || ${ctx.data} ${eq} null || ${ctx.data} ${eq} undefined`);
}
},
});
};
@ -102,36 +107,8 @@ export const ajvEnableDurationFormat = (ajv: Ajv) => {
});
};
// for (const keyword of [
// "name",
// "in",
// "example",
// "parameters",
// "externalDocs",
// "x-nullable",
// "x-ms-enum",
// "x-ms-azure-resource",
// "x-ms-parameter-location",
// "x-ms-client-name",
// "x-ms-external",
// "x-ms-skip-url-encoding",
// "x-ms-client-flatten",
// "x-ms-api-version",
// "x-ms-parameter-grouping",
// "x-ms-discriminator-value",
// "x-ms-client-request-id",
// "x-apim-code-nillable",
// "x-new-pattern",
// "x-previous-pattern",
// "x-comment",
// "x-abstract",
// "allowEmptyValue",
// "collectionFormat",
// ]) {
// ajv.addKeyword(keyword, {});
// }
export const ajvEnableAll = (ajv: Ajv, jsonLoader: JsonLoader) => {
addAjvFormats(ajv);
ajvEnableDiscriminatorMap(ajv, jsonLoader);
ajvEnableXmsSecret(ajv);
ajvEnableReadOnlyAndXmsMutability(ajv);
@ -141,4 +118,33 @@ export const ajvEnableAll = (ajv: Ajv, jsonLoader: JsonLoader) => {
ajvEnableDateTimeRfc1123Format(ajv);
ajvAddFormatsDefaultValidation(ajv, "string", ["byte", "password", "file"]);
ajvAddFormatsDefaultValidation(ajv, "number", ["double", "float", "decimal"]);
ajv.addVocabulary([
"name",
"in",
"example",
"parameters",
"externalDocs",
"x-nullable",
"x-ms-enum",
"x-ms-azure-resource",
"x-ms-parameter-location",
"x-ms-client-name",
"x-ms-external",
"x-ms-examples",
"x-ms-skip-url-encoding",
"x-ms-client-flatten",
"x-ms-api-version",
"x-ms-parameter-grouping",
"x-ms-discriminator-value",
"x-ms-client-request-id",
"x-apim-code-nillable",
"x-new-pattern",
"x-previous-pattern",
"x-comment",
"x-abstract",
"allowEmptyValue",
"collectionFormat",
"_skipError",
"discriminator",
]);
};

Просмотреть файл

@ -6,7 +6,10 @@ export const ajvEnableDiscriminatorMap = (ajv: Ajv, loader: JsonLoader) => {
ajv.addKeyword({
keyword: "discriminatorMap",
errors: "full",
metaSchema: { type: "object", additionalProperty: { type: "object,null" } },
metaSchema: {
type: "object",
additionalProperties: { type: "object", nullable: true },
},
compile(schemas: { [key: string]: Schema }, parentSch) {
const parentSchema = parentSch as Schema;

Просмотреть файл

@ -28,8 +28,6 @@ export class AjvSchemaValidator implements SchemaValidator {
public constructor(loader: JsonLoader, options?: Options) {
this.ajv = new Ajv({
// tslint:disable-next-line: no-submodule-imports
meta: require("ajv/lib/refs/json-schema-draft-04.json"),
strict: true,
strictTypes: true,
strictTuples: true,

Просмотреть файл

@ -49,6 +49,9 @@ const transformNullable = (s: Schema, jsonLoader: JsonLoader, defaultNullable?:
// Originally it's not nullable
if (nullable === false) {
if (sch.type === undefined) {
sch.type = "object";
}
return s;
}
@ -66,6 +69,9 @@ const transformNullable = (s: Schema, jsonLoader: JsonLoader, defaultNullable?:
} as Schema;
} else {
sch.nullable = true;
if (sch.type === undefined) {
sch.type = "object";
}
return sch;
}
};

Просмотреть файл

@ -9,7 +9,7 @@ export const pureObjectTransformer: GlobalTransformer = {
(sch.properties === undefined || Object.keys(sch.properties).length === 0) &&
sch.additionalProperties === undefined
) {
delete sch.type;
sch.type = ["object", "array"]
}
}
},

8
package-lock.json сгенерированный
Просмотреть файл

@ -2543,6 +2543,14 @@
}
}
},
"ajv-formats": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-0.6.1.tgz",
"integrity": "sha512-Zze3O7jGabuY4ospj2s8Jvjf5aGNaiwrFRqEdWdHs9oJd6IFXuWuS3ZHbJjyJvkjlDGncGQEBYnPRY9DoyaXgA==",
"requires": {
"ajv": "^7.0.0-beta.7"
}
},
"amdefine": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",

Просмотреть файл

@ -13,6 +13,7 @@
"@microsoft.azure/autorest-extension-base": "1.0.13",
"@azure-tools/openapi-tools-common": "^1.2.2",
"ajv": "7.0.0-beta.8",
"ajv-formats": "^0.6.1",
"commonmark": "^0.29.0",
"glob": "^7.1.2",
"globby": "^9.2.0",