@kevinoid/openapi-transformers 0.1.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/LICENSE.txt +19 -0
- package/README.md +134 -0
- package/add-tag-to-operation-ids.js +60 -0
- package/add-x-ms-enum-name.js +96 -0
- package/add-x-ms-enum-value-names.js +142 -0
- package/additional-properties-to-object.js +35 -0
- package/additional-properties-to-unconstrained.js +115 -0
- package/any-of-null-to-nullable.js +50 -0
- package/assert-properties.js +56 -0
- package/binary-string-to-file.js +54 -0
- package/bool-enum-to-bool.js +100 -0
- package/clear-html-response-schema.js +77 -0
- package/client-params-to-global.js +97 -0
- package/const-to-enum.js +49 -0
- package/escape-enum-values.js +211 -0
- package/exclusive-min-max-to-bool.js +61 -0
- package/format-to-type.js +54 -0
- package/index.js +94 -0
- package/inline-non-object-schemas.js +120 -0
- package/lib/component-manager.js +60 -0
- package/lib/matching-component-manager.js +74 -0
- package/lib/matching-parameter-manager.js +36 -0
- package/merge-all-of.js +60 -0
- package/merge-any-of.js +48 -0
- package/merge-one-of.js +48 -0
- package/nullable-not-required.js +240 -0
- package/nullable-to-type-null.js +46 -0
- package/openapi31to30.js +54 -0
- package/package.json +131 -0
- package/path-parameters-to-operations.js +63 -0
- package/pattern-properties-to-additional-properties.js +62 -0
- package/queries-to-x-ms-paths.js +63 -0
- package/read-only-not-required.js +111 -0
- package/ref-path-parameters.js +73 -0
- package/remove-default-only-response-produces.js +58 -0
- package/remove-paths-with-servers.js +34 -0
- package/remove-query-from-paths.js +526 -0
- package/remove-ref-siblings.js +78 -0
- package/remove-request-body.js +102 -0
- package/remove-response-headers.js +42 -0
- package/remove-security-scheme-if.js +166 -0
- package/remove-type-if.js +65 -0
- package/rename-components.js +285 -0
- package/replaced-by-to-description.js +50 -0
- package/server-vars-to-path-params.js +224 -0
- package/server-vars-to-x-ms-parameterized-host.js +247 -0
- package/type-null-to-enum.js +47 -0
- package/type-null-to-nullable.js +57 -0
- package/urlencoded-to-string.js +160 -0
- package/x-enum-to-ms.js +92 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright 2019-2024 Kevin Locke <kevin@kevinlocke.name>
|
|
3
|
+
* @license MIT
|
|
4
|
+
* @module "openapi-transformers/nullable-not-required.js"
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import OpenApiTransformerBase from 'openapi-transformer-base';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Determines whether a given Schema can have a null value.
|
|
11
|
+
*
|
|
12
|
+
* @param {!object} schema OpenAPI Schema object.
|
|
13
|
+
* @param {boolean} hasNullType Whether 'null' is a valid Schema type.
|
|
14
|
+
* @param {boolean} refNullable Treat $ref as nullable.
|
|
15
|
+
* @returns {boolean} <c>true</c> if <c>null</c> is a valid value for
|
|
16
|
+
* <c>schema</c>.
|
|
17
|
+
*/
|
|
18
|
+
function isNullable(schema, hasNullType, refNullable) {
|
|
19
|
+
const {
|
|
20
|
+
$ref,
|
|
21
|
+
nullable,
|
|
22
|
+
'x-nullable': xNullable,
|
|
23
|
+
type,
|
|
24
|
+
} = schema;
|
|
25
|
+
|
|
26
|
+
if ($ref) {
|
|
27
|
+
if (typeof nullable === 'boolean') {
|
|
28
|
+
return nullable;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (typeof xNullable === 'boolean') {
|
|
32
|
+
return xNullable;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return refNullable;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (hasNullType) {
|
|
39
|
+
if (typeof type === 'string') {
|
|
40
|
+
if (type !== 'null') {
|
|
41
|
+
// null forbidden by non-null type
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
} else if (Array.isArray(type)
|
|
45
|
+
&& !type.includes('null')) {
|
|
46
|
+
// null forbidden by null not in types
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
} else if (!nullable && !xNullable) {
|
|
50
|
+
// Without null type, null is only allowed with nullable (or x-nullable)
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Determines whether a given property of a given schema can have a null value.
|
|
59
|
+
*
|
|
60
|
+
* @param {!object} schema OpenAPI Schema object.
|
|
61
|
+
* @param {string} propName Name of property to check.
|
|
62
|
+
* @param {boolean} hasNullType Whether 'null' is a valid Schema type.
|
|
63
|
+
* @param {boolean} refNullable Treat $ref as nullable.
|
|
64
|
+
* @returns {?boolean} <c>true</c> if <c>null</c> is known to be a valid value
|
|
65
|
+
* for <c>propName</c> in <c>schema</c>, <c>false</c> if <c>null</c> is known
|
|
66
|
+
* to be an invalid value for <c>propName</c> in <c>schema</c>.
|
|
67
|
+
* <c>undefined</c> if <c>propName</c> is not constrained by <c>schema</c>.
|
|
68
|
+
*/
|
|
69
|
+
function isPropNullable(schema, propName, hasNullType, refNullable) {
|
|
70
|
+
const {
|
|
71
|
+
additionalProperties,
|
|
72
|
+
allOf,
|
|
73
|
+
anyOf,
|
|
74
|
+
oneOf,
|
|
75
|
+
properties,
|
|
76
|
+
} = schema;
|
|
77
|
+
let constrained = false;
|
|
78
|
+
const propSchema = properties?.[propName];
|
|
79
|
+
if (propSchema) {
|
|
80
|
+
constrained = true;
|
|
81
|
+
if (!isNullable(propSchema, hasNullType, refNullable)) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
} else if (additionalProperties) {
|
|
85
|
+
constrained = true;
|
|
86
|
+
if (!isNullable(additionalProperties, hasNullType, refNullable)) {
|
|
87
|
+
// schema in additionalProperties does not allow null
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
} else if (additionalProperties === false) {
|
|
91
|
+
// would fail validation if property is present
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (Array.isArray(allOf)) {
|
|
96
|
+
for (const allSchema of allOf) {
|
|
97
|
+
switch (isPropNullable(allSchema, propName, hasNullType, refNullable)) {
|
|
98
|
+
case false:
|
|
99
|
+
// If an allOf schema doesn't allow null, it's not allowed.
|
|
100
|
+
return false;
|
|
101
|
+
|
|
102
|
+
case true:
|
|
103
|
+
// An allOf schema allows null
|
|
104
|
+
constrained = true;
|
|
105
|
+
break;
|
|
106
|
+
|
|
107
|
+
default:
|
|
108
|
+
// An allOf schema doesn't constrain propName
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (Array.isArray(anyOf)) {
|
|
115
|
+
let anyNullable = false;
|
|
116
|
+
let anyUnconstrained = false;
|
|
117
|
+
for (const anySchema of anyOf) {
|
|
118
|
+
switch (isPropNullable(anySchema, propName, hasNullType, refNullable)) {
|
|
119
|
+
case false:
|
|
120
|
+
// An anyOf schema disallows null
|
|
121
|
+
break;
|
|
122
|
+
|
|
123
|
+
case true:
|
|
124
|
+
// An anyOf schema allows null
|
|
125
|
+
anyNullable = true;
|
|
126
|
+
break;
|
|
127
|
+
|
|
128
|
+
default:
|
|
129
|
+
// An anyOf schema doesn't constrain propName
|
|
130
|
+
anyUnconstrained = true;
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (!anyNullable && !anyUnconstrained) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (!anyUnconstrained) {
|
|
140
|
+
constrained = true;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (Array.isArray(oneOf)) {
|
|
145
|
+
let anyNullable = false;
|
|
146
|
+
let anyUnconstrained = false;
|
|
147
|
+
for (const oneSchema of oneOf) {
|
|
148
|
+
switch (isPropNullable(oneSchema, propName, hasNullType, refNullable)) {
|
|
149
|
+
case false:
|
|
150
|
+
// A oneOf schema disallows null
|
|
151
|
+
break;
|
|
152
|
+
|
|
153
|
+
case true:
|
|
154
|
+
// A oneOf schema allows null
|
|
155
|
+
anyNullable = true;
|
|
156
|
+
break;
|
|
157
|
+
|
|
158
|
+
default:
|
|
159
|
+
// A oneOf schema doesn't constrain propName
|
|
160
|
+
anyUnconstrained = true;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!anyNullable && !anyUnconstrained) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!anyUnconstrained) {
|
|
170
|
+
constrained = true;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return constrained ? true : undefined;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Transformer to make properties which are nullable non-required to work around
|
|
179
|
+
* partial support for x-nullable in Autorest. Currently nullable data types
|
|
180
|
+
* are used (e.g. Nullable<int>) but the Validate() method doesn't allow null.
|
|
181
|
+
* See: https://github.com/Azure/autorest/issues/3300
|
|
182
|
+
*/
|
|
183
|
+
export default class NullableNotRequiredTransformer
|
|
184
|
+
extends OpenApiTransformerBase {
|
|
185
|
+
hasNullType = undefined;
|
|
186
|
+
|
|
187
|
+
refNullable = false;
|
|
188
|
+
|
|
189
|
+
requireUnconstrained = false;
|
|
190
|
+
|
|
191
|
+
constructor(options) {
|
|
192
|
+
super();
|
|
193
|
+
this.refNullable = Boolean(options?.refNullable);
|
|
194
|
+
this.requireUnconstrained = Boolean(options?.requireUnconstrained);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
transformSchema(schema) {
|
|
198
|
+
const newSchema = super.transformSchema(schema);
|
|
199
|
+
if (!Array.isArray(newSchema?.required)
|
|
200
|
+
|| newSchema.required.length === 0) {
|
|
201
|
+
// No properties are required. None to remove.
|
|
202
|
+
return newSchema;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const transformed = {
|
|
206
|
+
...newSchema,
|
|
207
|
+
required: newSchema.required
|
|
208
|
+
.filter(
|
|
209
|
+
(reqName) => !(isPropNullable(
|
|
210
|
+
newSchema,
|
|
211
|
+
reqName,
|
|
212
|
+
this.hasNullType,
|
|
213
|
+
this.refNullable,
|
|
214
|
+
) ?? !this.requireUnconstrained),
|
|
215
|
+
),
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
if (transformed.required.length === 0) {
|
|
219
|
+
delete transformed.required;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return transformed;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
transformOpenApi(openApi) {
|
|
226
|
+
const version = openApi?.openapi || openApi?.swagger;
|
|
227
|
+
const verParts = version ? String(version).split('.').map(Number) : [];
|
|
228
|
+
if (verParts[0] > 3 || (verParts[0] === 3 && verParts[1] >= 1)) {
|
|
229
|
+
this.hasNullType = true;
|
|
230
|
+
} else if (verParts[0] < 3 || (verParts[0] === 3 && verParts[1] < 1)) {
|
|
231
|
+
this.hasNullType = false;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
return super.transformOpenApi(openApi);
|
|
236
|
+
} finally {
|
|
237
|
+
this.hasNullType = undefined;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright 2021 Kevin Locke <kevin@kevinlocke.name>
|
|
3
|
+
* @license MIT
|
|
4
|
+
* @module "openapi-transformers/nullable-to-type-null.js"
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import OpenApiTransformerBase from 'openapi-transformer-base';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Transformer to add `'null'` to `type` of Schema Objects with
|
|
11
|
+
* `nullable: true` or `x-nullable: true`.
|
|
12
|
+
*
|
|
13
|
+
* This is useful for converting from OpenAPI 2.0/3.0 to OpenAPI 3.1 or
|
|
14
|
+
* JSON Schema.
|
|
15
|
+
*/
|
|
16
|
+
export default class NullableToTypeNullTransformer
|
|
17
|
+
extends OpenApiTransformerBase {
|
|
18
|
+
transformSchema(schema) {
|
|
19
|
+
schema = super.transformSchema(schema);
|
|
20
|
+
if (schema === null
|
|
21
|
+
|| typeof schema !== 'object'
|
|
22
|
+
|| Array.isArray(schema)) {
|
|
23
|
+
return schema;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const {
|
|
27
|
+
nullable,
|
|
28
|
+
'x-nullable': xNullable,
|
|
29
|
+
...schemaNoNullable
|
|
30
|
+
} = schema;
|
|
31
|
+
if (nullable !== true && xNullable !== true) {
|
|
32
|
+
return schema;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const { type } = schema;
|
|
36
|
+
if (Array.isArray(type)) {
|
|
37
|
+
if (!type.includes('null')) {
|
|
38
|
+
schemaNoNullable.type = [...type, 'null'];
|
|
39
|
+
}
|
|
40
|
+
} else if (type !== undefined) {
|
|
41
|
+
schemaNoNullable.type = [type, 'null'];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return schemaNoNullable;
|
|
45
|
+
}
|
|
46
|
+
}
|
package/openapi31to30.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright 2021 Kevin Locke <kevin@kevinlocke.name>
|
|
3
|
+
* @license MIT
|
|
4
|
+
* @module "openapi-transformers/openapi31to30.js"
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import AnyOfNullToNullableTransformer from './any-of-null-to-nullable.js';
|
|
8
|
+
import ConstToEnumTransformer from './const-to-enum.js';
|
|
9
|
+
import ExclusiveMinMaxToBoolTransformer from './exclusive-min-max-to-bool.js';
|
|
10
|
+
import PatternPropertiesToAdditionalPropertiesTransformer
|
|
11
|
+
from './pattern-properties-to-additional-properties.js';
|
|
12
|
+
import RemoveTypeIfTransformer, { allNonNullTypes } from './remove-type-if.js';
|
|
13
|
+
import TypeNullToEnumTransformer from './type-null-to-enum.js';
|
|
14
|
+
import TypeNullToNullableTransformer from './type-null-to-nullable.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Transformer to convert an OpenAPI 3.1.* document to OpenAPI 3.0.3.
|
|
18
|
+
*/
|
|
19
|
+
export default class OpenApi31To30Transformer {
|
|
20
|
+
constructor() {
|
|
21
|
+
this.transformers = [
|
|
22
|
+
new ExclusiveMinMaxToBoolTransformer(),
|
|
23
|
+
new ConstToEnumTransformer(),
|
|
24
|
+
new AnyOfNullToNullableTransformer(),
|
|
25
|
+
new TypeNullToEnumTransformer(),
|
|
26
|
+
new TypeNullToNullableTransformer(),
|
|
27
|
+
new RemoveTypeIfTransformer(allNonNullTypes),
|
|
28
|
+
new PatternPropertiesToAdditionalPropertiesTransformer(),
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
transformOpenApi(openApi) {
|
|
33
|
+
if (typeof openApi !== 'object'
|
|
34
|
+
|| openApi === null
|
|
35
|
+
|| Array.isArray(openApi)) {
|
|
36
|
+
this.warn('Ignoring non-object OpenAPI', openApi);
|
|
37
|
+
return openApi;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (typeof openApi.openapi !== 'string'
|
|
41
|
+
|| !openApi.openapi.startsWith('3.1.')) {
|
|
42
|
+
this.warn('Expected OpenAPI 3.1, got', openApi.openapi);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
for (const transformer of this.transformers) {
|
|
46
|
+
openApi = transformer.transformOpenApi(openApi);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
...openApi,
|
|
51
|
+
openapi: '3.0.3',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kevinoid/openapi-transformers",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A collection of classes for transforming OpenAPI documents, particularly for compatibility with code generators like Autorest and OpenAPI Generator.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"autorest",
|
|
7
|
+
"openapi",
|
|
8
|
+
"openapi-transformer",
|
|
9
|
+
"swagger"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"homepage": "https://github.com/kevinoid/openapi-transformers",
|
|
13
|
+
"bugs": "https://github.com/kevinoid/openapi-transformers/issues",
|
|
14
|
+
"author": "Kevin Locke <kevin@kevinlocke.name>",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/kevinoid/openapi-transformers.git"
|
|
18
|
+
},
|
|
19
|
+
"type": "module",
|
|
20
|
+
"files": [
|
|
21
|
+
"*.js",
|
|
22
|
+
"!eslint.config.js",
|
|
23
|
+
"lib/",
|
|
24
|
+
"!**/.*"
|
|
25
|
+
],
|
|
26
|
+
"exports": {
|
|
27
|
+
".": "./index.js",
|
|
28
|
+
"./additional-properties-to-object.js": "./additional-properties-to-object.js",
|
|
29
|
+
"./additional-properties-to-unconstrained.js": "./additional-properties-to-unconstrained.js",
|
|
30
|
+
"./add-tag-to-operation-ids.js": "./add-tag-to-operation-ids.js",
|
|
31
|
+
"./add-x-ms-enum-name.js": "./add-x-ms-enum-name.js",
|
|
32
|
+
"./add-x-ms-enum-value-names.js": "./add-x-ms-enum-value-names.js",
|
|
33
|
+
"./any-of-null-to-nullable.js": "./any-of-null-to-nullable.js",
|
|
34
|
+
"./assert-properties.js": "./assert-properties.js",
|
|
35
|
+
"./binary-string-to-file.js": "./binary-string-to-file.js",
|
|
36
|
+
"./bool-enum-to-bool.js": "./bool-enum-to-bool.js",
|
|
37
|
+
"./clear-html-response-schema.js": "./clear-html-response-schema.js",
|
|
38
|
+
"./client-params-to-global.js": "./client-params-to-global.js",
|
|
39
|
+
"./const-to-enum.js": "./const-to-enum.js",
|
|
40
|
+
"./escape-enum-values.js": "./escape-enum-values.js",
|
|
41
|
+
"./exclusive-min-max-to-bool.js": "./exclusive-min-max-to-bool.js",
|
|
42
|
+
"./format-to-type.js": "./format-to-type.js",
|
|
43
|
+
"./inline-non-object-schemas.js": "./inline-non-object-schemas.js",
|
|
44
|
+
"./merge-all-of.js": "./merge-all-of.js",
|
|
45
|
+
"./merge-any-of.js": "./merge-any-of.js",
|
|
46
|
+
"./merge-one-of.js": "./merge-one-of.js",
|
|
47
|
+
"./nullable-not-required.js": "./nullable-not-required.js",
|
|
48
|
+
"./nullable-to-type-null.js": "./nullable-to-type-null.js",
|
|
49
|
+
"./openapi31to30.js": "./openapi31to30.js",
|
|
50
|
+
"./package.json": "./package.json",
|
|
51
|
+
"./path-parameters-to-operations.js": "./path-parameters-to-operations.js",
|
|
52
|
+
"./pattern-properties-to-additional-properties.js": "./pattern-properties-to-additional-properties.js",
|
|
53
|
+
"./queries-to-x-ms-paths.js": "./queries-to-x-ms-paths.js",
|
|
54
|
+
"./read-only-not-required.js": "./read-only-not-required.js",
|
|
55
|
+
"./ref-path-parameters.js": "./ref-path-parameters.js",
|
|
56
|
+
"./remove-default-only-response-produces.js": "./remove-default-only-response-produces.js",
|
|
57
|
+
"./remove-paths-with-servers.js": "./remove-paths-with-servers.js",
|
|
58
|
+
"./remove-query-from-paths.js": "./remove-query-from-paths.js",
|
|
59
|
+
"./remove-ref-siblings.js": "./remove-ref-siblings.js",
|
|
60
|
+
"./remove-request-body.js": "./remove-request-body.js",
|
|
61
|
+
"./remove-response-headers.js": "./remove-response-headers.js",
|
|
62
|
+
"./remove-security-scheme-if.js": "./remove-security-scheme-if.js",
|
|
63
|
+
"./remove-type-if.js": "./remove-type-if.js",
|
|
64
|
+
"./rename-components.js": "./rename-components.js",
|
|
65
|
+
"./replaced-by-to-description.js": "./replaced-by-to-description.js",
|
|
66
|
+
"./server-vars-to-path-params.js": "./server-vars-to-path-params.js",
|
|
67
|
+
"./server-vars-to-x-ms-parameterized-host.js": "./server-vars-to-x-ms-parameterized-host.js",
|
|
68
|
+
"./type-null-to-enum.js": "./type-null-to-enum.js",
|
|
69
|
+
"./type-null-to-nullable.js": "./type-null-to-nullable.js",
|
|
70
|
+
"./urlencoded-to-string.js": "./urlencoded-to-string.js",
|
|
71
|
+
"./x-enum-to-ms.js": "./x-enum-to-ms.js"
|
|
72
|
+
},
|
|
73
|
+
"//": "All scripts should run in POSIX sh and Windows cmd.exe",
|
|
74
|
+
"scripts": {
|
|
75
|
+
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -u",
|
|
76
|
+
"clean": "rimraf coverage && rimraf doc",
|
|
77
|
+
"doc": "npm run doc-js && npm run doc-spec",
|
|
78
|
+
"doc-js": "rimraf doc/api && jsdoc -c jsdoc.conf.json .",
|
|
79
|
+
"doc-spec": "rimraf doc/spec && mkdir doc/spec && mocha --reporter doc --recursive test | nodecat doc-src/spec/header.xhtml - doc-src/spec/footer.xhtml > doc/spec/index.xhtml",
|
|
80
|
+
"lint": "npm run lint-js && npm run lint-doc",
|
|
81
|
+
"lint-doc": "jsdoc -t templates/silent -c jsdoc-lint.conf.json . && echo JSDoc passed.",
|
|
82
|
+
"lint-js": "eslint --report-unused-disable-directives . && echo ESLint passed.",
|
|
83
|
+
"release": "git -C doc push && git push --follow-tags origin main gh-pages && echo \"Create a GitHub Release (from CHANGELOG.md) to run publish workflow.\"",
|
|
84
|
+
"postversion": "rimraf doc && git clone -b gh-pages -l -q . doc && npm run doc && git -C doc add . && git -C doc commit -n -m \"Docs for v$npm_package_version\"",
|
|
85
|
+
"preversion": "node ./scripts/preversion.js && npm run test-cov && c8 check-coverage --statements 85 --lines 85 && depcheck --ignore-dirs doc --ignores=\"eslint-*,rimraf\" && david && git-branch-is main && hub-ci-status -vv --wait",
|
|
86
|
+
"test": "npm run lint && npm run test-unit",
|
|
87
|
+
"test-cov": "npm run lint && npm run test-unit-cov",
|
|
88
|
+
"test-unit": "node --disable-proto=throw --throw-deprecation --unhandled-rejections=strict node_modules/mocha/bin/mocha.js --parallel --recursive test",
|
|
89
|
+
"test-unit-cov": "c8 --reporter=lcov --reporter=text npm run test-unit",
|
|
90
|
+
"version": "npm run changelog && echo && echo === Please edit CHANGELOG.md as desired, then exit === && echo && \"${npm_config_shell:-${SHELL:-bash}}\" && git commit -m \"Update CHANGELOG.md for $npm_package_version\" CHANGELOG.md",
|
|
91
|
+
"version-deps": "npm install conventional-changelog-cli david depcheck git-branch-is hub-ci-status"
|
|
92
|
+
},
|
|
93
|
+
"dependencies": {
|
|
94
|
+
"@kevinoid/dotnet-identifier-case": "^1.0.0",
|
|
95
|
+
"fast-json-stable-stringify": "^2.1.0",
|
|
96
|
+
"json-ptr": "^3.0.1",
|
|
97
|
+
"json-schema-intersect": "^0.1.0",
|
|
98
|
+
"openapi-transformer-base": "^1.1.0"
|
|
99
|
+
},
|
|
100
|
+
"devDependencies": {
|
|
101
|
+
"@kevinoid/eslint-config": "^34.0.0",
|
|
102
|
+
"c8": "^11.0.0",
|
|
103
|
+
"deep-freeze": "^0.0.1",
|
|
104
|
+
"eslint": "^9.35.0",
|
|
105
|
+
"globals": "^17.0.0",
|
|
106
|
+
"jsdoc": "^4.0.0",
|
|
107
|
+
"mocha": "^11.0.1",
|
|
108
|
+
"nodecat": "^3.0.0",
|
|
109
|
+
"rimraf": "^6.1.2"
|
|
110
|
+
},
|
|
111
|
+
"engines": {
|
|
112
|
+
"node": "20 || >=22",
|
|
113
|
+
"npm": ">=1.3.7"
|
|
114
|
+
},
|
|
115
|
+
"mocha": {
|
|
116
|
+
"checkLeaks": true,
|
|
117
|
+
"exit": false
|
|
118
|
+
},
|
|
119
|
+
"c8": {
|
|
120
|
+
"exclude": [
|
|
121
|
+
"test",
|
|
122
|
+
"test-lib"
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
"david": {
|
|
126
|
+
"// eslint": "Must match version from peerDependencies of @kevinoid/eslint-plugin",
|
|
127
|
+
"ignore": [
|
|
128
|
+
"eslint"
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright 2019 Kevin Locke <kevin@kevinlocke.name>
|
|
3
|
+
* @license MIT
|
|
4
|
+
* @module "openapi-transformers/path-parameters-to-operations.js"
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import OpenApiTransformerBase from 'openapi-transformer-base';
|
|
8
|
+
|
|
9
|
+
const PATH_METHODS = [
|
|
10
|
+
'delete',
|
|
11
|
+
'get',
|
|
12
|
+
'head',
|
|
13
|
+
'options',
|
|
14
|
+
'patch',
|
|
15
|
+
'post',
|
|
16
|
+
'put',
|
|
17
|
+
'trace',
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Transformer to move parameters defined on Path Item Objects to the beginning
|
|
22
|
+
* of the parameters array of the Operation Objects so that they will be
|
|
23
|
+
* generated in the desired order (path-first).
|
|
24
|
+
*/
|
|
25
|
+
export default class PathParametersToOperationTransformer
|
|
26
|
+
extends OpenApiTransformerBase {
|
|
27
|
+
// eslint-disable-next-line class-methods-use-this
|
|
28
|
+
transformPathItem(pathItem) {
|
|
29
|
+
if (!Array.isArray(pathItem.parameters)
|
|
30
|
+
|| pathItem.parameters.length === 0) {
|
|
31
|
+
return pathItem;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const {
|
|
35
|
+
parameters,
|
|
36
|
+
...newPathItem
|
|
37
|
+
} = pathItem;
|
|
38
|
+
for (const method of PATH_METHODS) {
|
|
39
|
+
if (Object.hasOwn(pathItem, method)) {
|
|
40
|
+
const operation = pathItem[method];
|
|
41
|
+
const opParams = operation.parameters;
|
|
42
|
+
newPathItem[method] = {
|
|
43
|
+
...operation,
|
|
44
|
+
// TODO: Operation parameters can override path parameters (where
|
|
45
|
+
// .name and .in match). Either can be $ref. Handle these.
|
|
46
|
+
parameters:
|
|
47
|
+
!Array.isArray(opParams) || opParams.length === 0 ? parameters
|
|
48
|
+
: [...parameters, ...opParams],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return newPathItem;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Performance optimization: Only need to transform paths.
|
|
57
|
+
transformOpenApi(spec) {
|
|
58
|
+
return {
|
|
59
|
+
...spec,
|
|
60
|
+
paths: this.transformPaths(spec.paths),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright 2021 Kevin Locke <kevin@kevinlocke.name>
|
|
3
|
+
* @license MIT
|
|
4
|
+
* @module "openapi-transformers/pattern-properties-to-additional-properties.js"
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
8
|
+
|
|
9
|
+
import OpenApiTransformerBase from 'openapi-transformer-base';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Transformer to combine any patternProperties into additionalProperties (for
|
|
13
|
+
* conversion from OpenAPI 3.1 to prior versions before patternProperties
|
|
14
|
+
* was supported).
|
|
15
|
+
* https://github.com/OAI/OpenAPI-Specification/issues/687
|
|
16
|
+
*/
|
|
17
|
+
export default class PatternPropertiesToAdditionalPropertiesTransformer
|
|
18
|
+
extends OpenApiTransformerBase {
|
|
19
|
+
transformSchema(schema) {
|
|
20
|
+
if (typeof schema !== 'object' || schema === null) {
|
|
21
|
+
return schema;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
schema = super.transformSchema(schema);
|
|
25
|
+
|
|
26
|
+
const {
|
|
27
|
+
patternProperties,
|
|
28
|
+
...newSchema
|
|
29
|
+
} = schema;
|
|
30
|
+
if (typeof patternProperties !== 'object' || patternProperties === null) {
|
|
31
|
+
return schema;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const uniquePropSchemas = [];
|
|
35
|
+
for (const propSchema of Object.values(patternProperties)) {
|
|
36
|
+
if (propSchema !== undefined
|
|
37
|
+
&& !uniquePropSchemas.some((s) => isDeepStrictEqual(s, propSchema))) {
|
|
38
|
+
uniquePropSchemas.push(propSchema);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (uniquePropSchemas.length === 0) {
|
|
43
|
+
// Remove empty patternProperties object.
|
|
44
|
+
return newSchema;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const { additionalProperties } = schema;
|
|
48
|
+
if (additionalProperties !== undefined
|
|
49
|
+
&& !uniquePropSchemas
|
|
50
|
+
.some((s) => isDeepStrictEqual(s, additionalProperties))) {
|
|
51
|
+
uniquePropSchemas.push(additionalProperties);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (uniquePropSchemas.length === 1) {
|
|
55
|
+
newSchema.additionalProperties = uniquePropSchemas[0];
|
|
56
|
+
} else {
|
|
57
|
+
newSchema.additionalProperties = { anyOf: uniquePropSchemas };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return newSchema;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright 2019 Kevin Locke <kevin@kevinlocke.name>
|
|
3
|
+
* @license MIT
|
|
4
|
+
* @module "openapi-transformers/queries-to-x-ms-paths.js"
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import assert from 'node:assert';
|
|
8
|
+
import { debuglog } from 'node:util';
|
|
9
|
+
|
|
10
|
+
import OpenApiTransformerBase from 'openapi-transformer-base';
|
|
11
|
+
|
|
12
|
+
const debug = debuglog('openapi-transformers:queries-to-x-ms-paths');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Transformer to move paths with query parameters from paths to x-ms-paths for
|
|
16
|
+
* Autorest.
|
|
17
|
+
*
|
|
18
|
+
* https://github.com/Azure/autorest/tree/master/docs/extensions#x-ms-paths
|
|
19
|
+
*
|
|
20
|
+
* This is used to work around lack of support for multiple operations with the
|
|
21
|
+
* same path and method:
|
|
22
|
+
* https://github.com/OAI/OpenAPI-Specification/issues/791
|
|
23
|
+
*
|
|
24
|
+
* Putting query in path is not allowed by any current version of OpenAPI
|
|
25
|
+
* https://github.com/OAI/OpenAPI-Specification/issues/468#issuecomment-142393969
|
|
26
|
+
* but it has the benefit of working with lots of tooling without support for
|
|
27
|
+
* x-ms-paths (e.g. for linting, docs generation, etc.)
|
|
28
|
+
*/
|
|
29
|
+
export default class QueriesToXMsPathsTransformer
|
|
30
|
+
extends OpenApiTransformerBase {
|
|
31
|
+
// Override as performance optimization, since only transforming paths
|
|
32
|
+
// eslint-disable-next-line class-methods-use-this
|
|
33
|
+
transformOpenApi(spec) {
|
|
34
|
+
if (!spec || !spec.paths) {
|
|
35
|
+
return spec;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const queryPaths = Object.keys(spec.paths)
|
|
39
|
+
.filter((path) => path.includes('?'));
|
|
40
|
+
|
|
41
|
+
if (queryPaths.length === 0) {
|
|
42
|
+
return spec;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const paths = { ...spec.paths };
|
|
46
|
+
const xMsPaths = { ...spec['x-ms-paths'] };
|
|
47
|
+
for (const path of queryPaths) {
|
|
48
|
+
debug('moving %s from paths to x-ms-paths', path);
|
|
49
|
+
assert.ok(
|
|
50
|
+
!Object.hasOwn(xMsPaths, path),
|
|
51
|
+
`${path} already present in x-ms-paths`,
|
|
52
|
+
);
|
|
53
|
+
xMsPaths[path] = paths[path];
|
|
54
|
+
delete paths[path];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
...spec,
|
|
59
|
+
paths,
|
|
60
|
+
'x-ms-paths': xMsPaths,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|