-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathurlencoded-to-string.js
160 lines (134 loc) · 4.27 KB
/
urlencoded-to-string.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/**
* @copyright Copyright 2020 Kevin Locke <kevin@kevinlocke.name>
* @license MIT
* @module "openapi-transformers/urlencoded-to-string.js"
*/
import OpenApiTransformerBase from 'openapi-transformer-base';
const consumesSymbol = Symbol('consumes');
function isFormData(mediaType) {
return /^multipart\/form-data\s*(?:;.*)?$/i.test(mediaType);
}
function isUrlencoded(mediaType) {
return /^application\/x-www-form-urlencoded\s*(?:;.*)?$/i.test(mediaType);
}
/**
* Transformer to change request parameter types to string for operations which
* only consume application/x-www-form-urlencoded, to work around
* https://github.com/Azure/autorest/issues/3449
*/
export default class UrlencodedToStringTransformer
extends OpenApiTransformerBase {
constructor() {
super();
this[consumesSymbol] = undefined;
}
transformSchema(schema) {
if (typeof schema !== 'object' || schema === null) {
return schema;
}
let newSchema = super.transformSchema(schema);
// Change primitive types to string
if (['number', 'integer', 'boolean'].includes(schema.type)) {
newSchema = {
...newSchema,
type: 'string',
};
// TODO: Optionally remove constraints which don't apply to string type?
// Older JSON Schema drafts (e.g. JSON Schema Draft 4 ref'd by OAS2)
// specify the instance is only valid if it satisfies the constraint.
// Newer JSON Schema drafts (e.g. Wright 00 ref'd by OAS3.1) specify
// the constraint is ignored for non-numbers.
// Autorest ignores these constraints on string properties.
// They may be useful as documentation for API developers.
// Is there a reason to remove them?
/*
delete newSchema.multipleOf;
delete newSchema.minimum;
delete newSchema.exclusiveMaximum;
delete newSchema.maximum;
delete newSchema.exclusiveMinimum;
*/
}
// Ensure enums are modeled as string
const { type, 'x-ms-enum': xMsEnum } = newSchema;
if (type === 'string'
&& xMsEnum
&& xMsEnum.modelAsString !== true) {
newSchema = { ...newSchema };
// Note: Could set modelAsString: true, but would cause conflict if any
// other params/schemas have same name
delete newSchema['x-ms-enum'];
}
// Note: There does not appear to be a need to remove validation properties
// (e.g. minimum, maximum, etc.) since Autorest ignores them for string
// properties.
return newSchema;
}
transformParameter(parameter) {
if (!parameter) {
return parameter;
}
if (parameter.in === 'formData') {
return this.transformSchema(parameter);
}
if (parameter.in === 'body' && parameter.schema) {
return {
...parameter,
schema: this.transformSchema(parameter.schema),
};
}
return parameter;
}
transformRequestBody(requestBody) {
if (!requestBody || !requestBody.content) {
return requestBody;
}
const { content } = requestBody;
const consumes = Object.keys(content);
const urlencoded = consumes.find(isUrlencoded);
if (!urlencoded) {
return requestBody;
}
return {
...requestBody,
content: {
...content,
[urlencoded]: this.transformMediaType(content[urlencoded]),
},
};
}
transformOperation(operation) {
if (!operation) {
return super.transformOperation(operation);
}
const { parameters, requestBody } = operation;
if (requestBody === undefined && !Array.isArray(parameters)) {
return operation;
}
const newOperation = { ...operation };
const consumes = operation.consumes || this[consumesSymbol];
if (parameters !== undefined
&& Array.isArray(consumes)
&& consumes.some(isUrlencoded)
&& !consumes.some(isFormData)) {
newOperation.parameters =
parameters.map(this.transformParameter.bind(this));
}
if (requestBody !== undefined) {
newOperation.requestBody =
this.transformRequestBody(newOperation.requestBody);
}
return newOperation;
}
transformOpenApi(openApi) {
this[consumesSymbol] = openApi.consumes;
try {
return {
...openApi,
paths: this.transformPaths(openApi.paths),
};
} finally {
this[consumesSymbol] = undefined;
}
}
}