@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
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright 2016 Kevin Locke <kevin@kevinlocke.name>. All rights reserved.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to
|
|
5
|
+
deal in the Software without restriction, including without limitation the
|
|
6
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
7
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
|
11
|
+
all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
18
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
19
|
+
IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
OpenAPI Transformers
|
|
2
|
+
====================
|
|
3
|
+
|
|
4
|
+
[](https://github.com/kevinoid/openapi-transformers/actions/workflows/node.js.yml?query=branch%3Amain)
|
|
5
|
+
[](https://app.codecov.io/gh/kevinoid/openapi-transformers/branch/main)
|
|
6
|
+
[](https://libraries.io/npm/@kevinoid%2Fopenapi-transformers)
|
|
7
|
+
[](https://www.npmjs.com/package/@kevinoid/openapi-transformers)
|
|
8
|
+
[](https://www.npmjs.com/package/@kevinoid/openapi-transformers)
|
|
9
|
+
|
|
10
|
+
A collection of classes for transforming
|
|
11
|
+
[OpenAPI](https://github.com/OAI/OpenAPI-Specification/) documents,
|
|
12
|
+
particularly for compatibility with code generators like
|
|
13
|
+
[Autorest](https://github.com/Azure/autorest) and [OpenAPI
|
|
14
|
+
Generator](https://openapi-generator.tech/).
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## Introductory Example
|
|
18
|
+
|
|
19
|
+
To rename all Schema Objects defined in `components` of an OpenAPI document:
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
import RenameComponentsTransformer from '@kevinoid/openapi-transformers';
|
|
23
|
+
import openapi from './openapi.json' with { type: 'json' };
|
|
24
|
+
|
|
25
|
+
function renameSchema(schemaName) {
|
|
26
|
+
return `New${schemaName}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const transformer = new RenameComponentsTransformer({ schemas: renameSchema });
|
|
30
|
+
console.log(transformer.transformOpenApi(openapi));
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
## Example with [`@kevinoid/openapi-transformer-cli`](https://github.com/kevinoid/openapi-transformer-cli)
|
|
35
|
+
|
|
36
|
+
To remove `headers` from responses in an OpenAPI document:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
openapi-transformer -t @kevinoid/openapi-transformers/remove-response-headers.js <openapi-old.json >openapi-new.json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## Transformers
|
|
44
|
+
|
|
45
|
+
| **Transformer** | **Description** |
|
|
46
|
+
| ---------------------------------------------------------------------------------------------------- | --------------- |
|
|
47
|
+
| [AddTagToOperationIdsTransformer](add-tag-to-operation-ids.js) | Prefix `operationId` with the first tag name and an underscore. |
|
|
48
|
+
| [AddXMsEnumNameTransformer](add-x-ms-enum-name.js) | Add `x-ms-enum.name` from schema name, if not present. |
|
|
49
|
+
| [AddXMsEnumValueNamesTransformer](add-x-ms-enum-value-names.js) | Add `x-ms-enum.values.name` to enums where the name generated by Autorest differs from the Microsoft C# Capitalization Rules for Identifiers. |
|
|
50
|
+
| [AdditionalPropertiesToObjectTransformer](additional-properties-to-object.js) | Replace boolean `additionalProperties` with a Schema. |
|
|
51
|
+
| [AdditionalPropertiesToUnconstrainedTransformer](additional-properties-to-unconstrained.js) | Replace `additionalProperties` (and `patternProperties`) with an unconstrained schema alongside other properties. |
|
|
52
|
+
| [AnyOfNullToNullableTransformer](any-of-null-to-nullable.js) | Replace `type: 'null'` in `anyOf` with `nullable: true` (for OAS 3.0). |
|
|
53
|
+
| [BinaryStringToFileTransformer](binary-string-to-file.js) | Replace `type: string` with `format: binary` (or `format: file`) with `type: file`. |
|
|
54
|
+
| [BoolEnumToBoolTransformer](bool-enum-to-bool.js) | Replace `enum: [true, false]` with `type: boolean`. |
|
|
55
|
+
| [ClearHtmlResponseSchemaTransformer](clear-html-response-schema.js) | Remove response content for the `text/html` media type. |
|
|
56
|
+
| [ClientParamsToGlobalTransformer](client-params-to-global.js) | Move parameters with `x-ms-parameter-location: client` defined on Path Item Objects and Operation Objects to the Components or Definitions Object. |
|
|
57
|
+
| [ConstToEnumTransformer](const-to-enum.js) | Convert Schema Objects with `const` to `enum`. |
|
|
58
|
+
| [AssertPropertiesTransformer](assert-properties.js) | Throw an `Error` when given properties are present. |
|
|
59
|
+
| [EscapeEnumValuesTransformer](escape-enum-values.js) | Escape string enum values appropriately for C# string literals. |
|
|
60
|
+
| [ExclusiveMinMaxToBoolTransformer](exclusive-min-max-to-bool.js) | Convert Schema Objects with numeric values for `exclusiveMaximum` and/or `exclusiveMinimum` to boolean values with corresponding `maximum` and/or `minimum`. |
|
|
61
|
+
| [FormatToTypeTransformer](format-to-type.js) | Convert known formats in an OAS3 doc to types. |
|
|
62
|
+
| [InlineNonObjectSchemaTransformer](inline-non-object-schemas.js) | Inline schemas with non-object type. |
|
|
63
|
+
| [MergeAllOfTransformer](merge-all-of.js) | Merge `allOf` schemas into the parent schema. |
|
|
64
|
+
| [MergeAnyOfTransformer](merge-any-of.js) | Merge `anyOf` schemas into the parent schema. |
|
|
65
|
+
| [MergeOneOfTransformer](merge-one-of.js) | Merge `oneOf` schemas into the parent schema. |
|
|
66
|
+
| [NullableNotRequiredTransformer](nullable-not-required.js) | Make properties which are `nullable` non-`required`. |
|
|
67
|
+
| [NullableToTypeNullTransformer](nullable-to-type-null.js) | Add `'null'` to `type` of Schema Objects with `nullable: true` or `x-nullable: true`. |
|
|
68
|
+
| [OpenApi31To30Transformer](openapi31to30.js) | Convert an OpenAPI 3.1.* document to OpenAPI 3.0.3. |
|
|
69
|
+
| [PathParametersToOperationTransformer](path-parameters-to-operations.js) | Move parameters defined on Path Item Objects to the beginning of the parameters array of the Operation Objects. |
|
|
70
|
+
| [PatternPropertiesToAdditionalPropertiesTransformer](pattern-properties-to-additional-properties.js) | Combine any `patternProperties` into `additionalProperties`. |
|
|
71
|
+
| [QueriesToXMsPathsTransformer](queries-to-x-ms-paths.js) | Move paths with query parameters from `paths` to `x-ms-paths`. |
|
|
72
|
+
| [ReadOnlyNotRequiredTransformer](read-only-not-required.js) | Ensure `readOnly` schema properties are not `required`. |
|
|
73
|
+
| [RefPathParametersTransformer](ref-path-parameters.js) | Move Parameters defined on Path Item Objects to global parameters which are referenced in the Path Item. |
|
|
74
|
+
| [RemoveDefaultOnlyResponseProducesTransformer](remove-default-only-response-produces.js) | Remove `produces` from Operations with only a default response. |
|
|
75
|
+
| [RemovePathsWithServersTransformer](remove-paths-with-servers.js) | Remove Path Item Objects which have `servers`. |
|
|
76
|
+
| [RemoveQueryFromPathsTransformer](remove-query-from-paths.js) | Remove query component of path in Paths Object. |
|
|
77
|
+
| [RemoveRefSiblingsTransformer](remove-ref-siblings.js) | Remove properties from Reference Objects. |
|
|
78
|
+
| [RemoveRequestBodyTransformer](remove-request-body.js) | Remove `requestBody` from operations on a given set of HTTP methods. |
|
|
79
|
+
| [RemoveResponseHeadersTransformer](remove-response-headers.js) | Remove `headers` from Response objects.
|
|
80
|
+
| [RemoveSecuritySchemeIfTransformer](remove-security-scheme-if.js) | Remove `security` schemes matching a given predicate. |
|
|
81
|
+
| [RemoveTypeIfTransformer](remove-type-if.js) | Remove `type` from Schema Objects where `type` matches a given predicate. |
|
|
82
|
+
| [RenameComponentsTransformer](rename-components.js) | Rename `components`. |
|
|
83
|
+
| [ReplacedByToDescriptionTransformer](replaced-by-to-description.js) | Convert `x-deprecated.replaced-by` to `x-deprecated.description`, if not present. |
|
|
84
|
+
| [ServerVarsToPathParamsTransformer](server-vars-to-path-params.js) | Convert Server Variables in path portion to Parameters on Path Item Objects. |
|
|
85
|
+
| [ServerVarsToParamHostTransformer](server-vars-to-x-ms-parameterized-host.js) | Convert Server Variables in host portion to `x-ms-parameterized-host`. |
|
|
86
|
+
| [TypeNullToEnumTransformer](type-null-to-enum.js) | Convert Schema Objects with `type: 'null'` to `enum: [null]`. |
|
|
87
|
+
| [TypeNullToNullableTransformer](type-null-to-nullable.js) | Convert Schema Objects with `'null'` in `type` to `nullable: true`. |
|
|
88
|
+
| [UrlencodedToStringTransformer](urlencoded-to-string.js) | Change request parameter types to string for operations which only consume `application/x-www-form-urlencoded`. |
|
|
89
|
+
| [XEnumToXMsEnumTransformer](x-enum-to-ms.js) | Convert `x-enum-descriptions` and `x-enum-varnames` to `x-ms-enum`. |
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
## Installation
|
|
93
|
+
|
|
94
|
+
[This package](https://www.npmjs.com/package/@kevinoid/openapi-transformers) can be
|
|
95
|
+
installed using [npm](https://www.npmjs.com/), either globally or locally, by
|
|
96
|
+
running:
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
npm install @kevinoid/openapi-transformers
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
## Recipes
|
|
104
|
+
|
|
105
|
+
More examples can be found in the [test
|
|
106
|
+
specifications](https://kevinoid.github.io/openapi-transformers/spec).
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
## API Docs
|
|
110
|
+
|
|
111
|
+
To use this module as a library, see the [API
|
|
112
|
+
Documentation](https://kevinoid.github.io/openapi-transformers/api).
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
## Contributing
|
|
116
|
+
|
|
117
|
+
Contributions are appreciated. Contributors agree to abide by the [Contributor
|
|
118
|
+
Covenant Code of
|
|
119
|
+
Conduct](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html).
|
|
120
|
+
If this is your first time contributing to a Free and Open Source Software
|
|
121
|
+
project, consider reading [How to Contribute to Open
|
|
122
|
+
Source](https://opensource.guide/how-to-contribute/)
|
|
123
|
+
in the Open Source Guides.
|
|
124
|
+
|
|
125
|
+
If the desired change is large, complex, backwards-incompatible, can have
|
|
126
|
+
significantly differing implementations, or may not be in scope for this
|
|
127
|
+
project, opening an issue before writing the code can avoid frustration and
|
|
128
|
+
save a lot of time and effort.
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
This project is available under the terms of the [MIT License](LICENSE.txt).
|
|
134
|
+
See the [summary at TLDRLegal](https://tldrlegal.com/license/mit-license).
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright 2019 Kevin Locke <kevin@kevinlocke.name>
|
|
3
|
+
* @license MIT
|
|
4
|
+
* @module "openapi-transformers/add-tag-to-operation-ids.js"
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { debuglog } from 'node:util';
|
|
8
|
+
|
|
9
|
+
import OpenApiTransformerBase from 'openapi-transformer-base';
|
|
10
|
+
|
|
11
|
+
const debug = debuglog('add-tag-to-operation-ids');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Transformer to prefix operationId with the first tag name and an underscore,
|
|
15
|
+
* which Autorest recognizes as an "operation group" represented by a separate
|
|
16
|
+
* API class when generating the client.
|
|
17
|
+
*
|
|
18
|
+
* See https://github.com/Azure/autorest/issues/1497#issuecomment-252082163
|
|
19
|
+
*/
|
|
20
|
+
export default class AddTagToOperationIdsTransformer
|
|
21
|
+
extends OpenApiTransformerBase {
|
|
22
|
+
constructor({ tagSuffix = '' } = {}) {
|
|
23
|
+
super();
|
|
24
|
+
this.tagSuffix = String(tagSuffix);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
transformOperation(op) {
|
|
28
|
+
if (op === null || typeof op !== 'object') {
|
|
29
|
+
debug('Not adding tag to non-object operation %O', op);
|
|
30
|
+
return op;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const { tags } = op;
|
|
34
|
+
if (!Array.isArray(tags) || tags.length === 0) {
|
|
35
|
+
debug('No tag to add for operation %O', op);
|
|
36
|
+
return op;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const { operationId } = op;
|
|
40
|
+
if (operationId === undefined
|
|
41
|
+
|| operationId === null
|
|
42
|
+
|| operationId === '') {
|
|
43
|
+
debug('No operationId to add for operation %O', op);
|
|
44
|
+
return op;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
...op,
|
|
49
|
+
operationId: `${tags[0]}${this.tagSuffix}_${operationId}`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Override as performance optimization, since only transforming paths
|
|
54
|
+
transformOpenApi(spec) {
|
|
55
|
+
return {
|
|
56
|
+
...spec,
|
|
57
|
+
paths: this.transformPaths(spec.paths),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright 2019 Kevin Locke <kevin@kevinlocke.name>
|
|
3
|
+
* @license MIT
|
|
4
|
+
* @module "openapi-transformers/add-x-ms-enum-name.js"
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import OpenApiTransformerBase from 'openapi-transformer-base';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Transformer to add x-ms-enum.name from schema name, if not present
|
|
11
|
+
* (so Autorest will generate enum types).
|
|
12
|
+
*
|
|
13
|
+
* https://github.com/Azure/autorest/tree/master/docs/extensions#x-ms-enum
|
|
14
|
+
*/
|
|
15
|
+
export default class AddXMsEnumNameTransformer extends OpenApiTransformerBase {
|
|
16
|
+
// eslint-disable-next-line class-methods-use-this
|
|
17
|
+
transformSchema(schema, schemaName) {
|
|
18
|
+
if (!schema.enum || (schema['x-ms-enum'] && schema['x-ms-enum'].name)) {
|
|
19
|
+
return schema;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
...schema,
|
|
24
|
+
'x-ms-enum': {
|
|
25
|
+
...schema['x-ms-enum'],
|
|
26
|
+
name: schemaName,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Transforms Map[string,Schema] with named schemas by passing the
|
|
32
|
+
* name as the second argument to transformSchema.
|
|
33
|
+
*
|
|
34
|
+
* @param {!Object<string,object>|*} schemas Schmea map to transform.
|
|
35
|
+
* @returns {!Object<string,object>|*} If obj is a Map, a plain object with
|
|
36
|
+
* the same own enumerable string-keyed properties as obj with values
|
|
37
|
+
* returned by transformSchema. Otherwise, obj is returned unchanged.
|
|
38
|
+
*/
|
|
39
|
+
transformSchemas(schemas) {
|
|
40
|
+
if (typeof schemas !== 'object'
|
|
41
|
+
|| schemas === null
|
|
42
|
+
|| Array.isArray(schemas)) {
|
|
43
|
+
return schemas;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const newSchemas = { ...schemas };
|
|
47
|
+
for (const [schemaName, schema] of Object.entries(schemas)) {
|
|
48
|
+
if (schema !== undefined) {
|
|
49
|
+
newSchemas[schemaName] = this.transformSchema(schema, schemaName);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return newSchemas;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Optimization: Only transform schemas
|
|
57
|
+
transformComponents(components) {
|
|
58
|
+
if (!components) {
|
|
59
|
+
return components;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const { schemas } = components;
|
|
63
|
+
if (!schemas) {
|
|
64
|
+
return components;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
...components,
|
|
69
|
+
schemas: this.transformSchemas(schemas),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Optimization: Only transform components/definitions
|
|
74
|
+
transformOpenApi(openApi) {
|
|
75
|
+
if (!openApi) {
|
|
76
|
+
return openApi;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const { components, definitions } = openApi;
|
|
80
|
+
if (!components && !definitions) {
|
|
81
|
+
return openApi;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const newOpenApi = { ...openApi };
|
|
85
|
+
|
|
86
|
+
if (components) {
|
|
87
|
+
newOpenApi.components = this.transformComponents(components);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (definitions) {
|
|
91
|
+
newOpenApi.definitions = this.transformSchemas(definitions);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return newOpenApi;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright 2019 Kevin Locke <kevin@kevinlocke.name>
|
|
3
|
+
* @license MIT
|
|
4
|
+
* @module "openapi-transformers/add-x-ms-enum-value-names.js"
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import assert from 'node:assert';
|
|
8
|
+
|
|
9
|
+
import dotnetCase from '@kevinoid/dotnet-identifier-case';
|
|
10
|
+
import OpenApiTransformerBase from 'openapi-transformer-base';
|
|
11
|
+
|
|
12
|
+
assert.ok(/\p{L}/u.test('X'), 'Unicode property escapes are supported.');
|
|
13
|
+
|
|
14
|
+
function firstToLower(word) {
|
|
15
|
+
if (!word) {
|
|
16
|
+
return word;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Lower-case 2-letter acronym together (as Autorest does)
|
|
20
|
+
if (word.length === 2 && word === word.toUpperCase()) {
|
|
21
|
+
return word.toLowerCase();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return word.charAt(0).toLowerCase() + word.slice(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function firstToUpper(word) {
|
|
28
|
+
if (!word) {
|
|
29
|
+
return word;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Returns the enum member name which would be used by Autorest.
|
|
36
|
+
* https://github.com/Azure/autorest.common/blob/54c21af/src/CodeNamer.cs#L178
|
|
37
|
+
*
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
function autorestEnumMemberName(value) {
|
|
41
|
+
const clean = value.replaceAll(/[^\p{L}\p{N}_-]/gu, '');
|
|
42
|
+
const words = clean.split(/[_-]/);
|
|
43
|
+
|
|
44
|
+
if (clean.charAt(0) === '_') {
|
|
45
|
+
// eslint-disable-next-line prefer-template
|
|
46
|
+
return '_' + words
|
|
47
|
+
.map((word, i) => (i > 0 ? firstToUpper(word) : firstToLower(word)))
|
|
48
|
+
.join('');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return words
|
|
52
|
+
.map(firstToUpper)
|
|
53
|
+
.join('');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function addXMsEnumValueNamesToSchema(schema) {
|
|
57
|
+
if (!schema.enum || !schema['x-ms-enum']) {
|
|
58
|
+
// Schema won't generate an enum
|
|
59
|
+
return schema;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const xMsEnum = schema['x-ms-enum'];
|
|
63
|
+
const xMsEnumValues = xMsEnum.values;
|
|
64
|
+
if (xMsEnumValues
|
|
65
|
+
&& xMsEnumValues.every((v) => v.name !== null && v.name !== undefined)) {
|
|
66
|
+
// Names already specified for all values
|
|
67
|
+
return schema;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const values =
|
|
71
|
+
Array.isArray(xMsEnumValues) ? xMsEnumValues.map((v) => v.value)
|
|
72
|
+
: schema.enum;
|
|
73
|
+
const stringValues = values.map(String);
|
|
74
|
+
const autorestNames = stringValues.map(autorestEnumMemberName);
|
|
75
|
+
const microsoftNames = stringValues.map(dotnetCase);
|
|
76
|
+
|
|
77
|
+
let anyNameChanged = false;
|
|
78
|
+
let newXMsEnumValues;
|
|
79
|
+
if (Array.isArray(xMsEnumValues)) {
|
|
80
|
+
newXMsEnumValues = xMsEnumValues.map((xMsEnumValue, i) => {
|
|
81
|
+
if (xMsEnumValue.name !== null && xMsEnumValue.name !== undefined) {
|
|
82
|
+
return xMsEnumValue;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const autorestName = autorestNames[i];
|
|
86
|
+
const microsoftName = microsoftNames[i];
|
|
87
|
+
if (autorestName === microsoftName) {
|
|
88
|
+
return xMsEnumValue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
anyNameChanged = true;
|
|
92
|
+
return {
|
|
93
|
+
...xMsEnumValue,
|
|
94
|
+
name: microsoftName,
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
} else {
|
|
98
|
+
newXMsEnumValues = schema.enum.map((value, i) => {
|
|
99
|
+
const autorestName = autorestNames[i];
|
|
100
|
+
const microsoftName = microsoftNames[i];
|
|
101
|
+
const newXMsEnumValue = { value };
|
|
102
|
+
if (autorestName !== microsoftName) {
|
|
103
|
+
anyNameChanged = true;
|
|
104
|
+
newXMsEnumValue.name = microsoftName;
|
|
105
|
+
}
|
|
106
|
+
return newXMsEnumValue;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!anyNameChanged) {
|
|
111
|
+
return schema;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
...schema,
|
|
116
|
+
'x-ms-enum': {
|
|
117
|
+
...xMsEnum,
|
|
118
|
+
values: newXMsEnumValues,
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Transformer to add x-ms-enum.values.name to enums where the name generated by
|
|
125
|
+
* Autorest differs from the Microsoft C# Capitalization Rules for Identifiers.
|
|
126
|
+
*
|
|
127
|
+
* https://github.com/Azure/autorest/issues/3328
|
|
128
|
+
*/
|
|
129
|
+
export default class AddXMsEnumValueNamesTransformer
|
|
130
|
+
extends OpenApiTransformerBase {
|
|
131
|
+
transformSchema(schema) {
|
|
132
|
+
return addXMsEnumValueNamesToSchema(
|
|
133
|
+
super.transformSchema(schema),
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
transformParameter(parameter) {
|
|
138
|
+
return addXMsEnumValueNamesToSchema(
|
|
139
|
+
super.transformParameter(parameter),
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright 2019 Kevin Locke <kevin@kevinlocke.name>
|
|
3
|
+
* @license MIT
|
|
4
|
+
* @module "openapi-transformers/additional-properties-to-object.js"
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import OpenApiTransformerBase from 'openapi-transformer-base';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Transformer to replace boolean additionalProperties with an object schema to
|
|
11
|
+
* work around https://github.com/Azure/autorest/issues/3439.
|
|
12
|
+
*/
|
|
13
|
+
export default class AdditionalPropertiesToObjectTransformer
|
|
14
|
+
extends OpenApiTransformerBase {
|
|
15
|
+
transformSchema(schema) {
|
|
16
|
+
if (typeof schema !== 'object' || schema === null) {
|
|
17
|
+
return schema;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const newSchema = super.transformSchema(schema);
|
|
21
|
+
const { additionalProperties } = newSchema;
|
|
22
|
+
|
|
23
|
+
if (typeof additionalProperties !== 'boolean') {
|
|
24
|
+
return newSchema;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
...newSchema,
|
|
29
|
+
|
|
30
|
+
// Use schema equivalents described by current spec author Henry Andrews
|
|
31
|
+
// https://groups.google.com/d/msg/json-schema/Es0fEf3hj2Y/MxWmgercBAAJ
|
|
32
|
+
additionalProperties: additionalProperties ? {} : { not: {} },
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright 2019-2020 Kevin Locke <kevin@kevinlocke.name>
|
|
3
|
+
* @license MIT
|
|
4
|
+
* @module "openapi-transformers/additional-properties-to-unconstrained.js"
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import OpenApiTransformerBase from 'openapi-transformer-base';
|
|
8
|
+
|
|
9
|
+
/** Applies a predicate to each schema which contributes to the generated
|
|
10
|
+
* type of a given schema.
|
|
11
|
+
*
|
|
12
|
+
* @private
|
|
13
|
+
*/
|
|
14
|
+
function someCombinedSchema(schema, predicate) {
|
|
15
|
+
if (predicate(schema)) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (typeof schema !== 'object' || schema === null) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (['then', 'else'].some(
|
|
24
|
+
(key) => someCombinedSchema(schema[key], predicate),
|
|
25
|
+
)) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return ['allOf', 'anyOf', 'oneOf'].some(
|
|
30
|
+
(key) => Array.isArray(schema[key])
|
|
31
|
+
&& schema[key].some((s) => someCombinedSchema(s, predicate)),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Replaces additionalProperties (and patternProperties) in each schema which
|
|
36
|
+
* contributes to the generated type of a given schema.
|
|
37
|
+
*
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
function replaceAdditionalProperties(schema) {
|
|
41
|
+
if (typeof schema !== 'object' || schema === null) {
|
|
42
|
+
return schema;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const newSchema = { ...schema };
|
|
46
|
+
|
|
47
|
+
for (const key of ['additionalProperties', 'patternProperties']) {
|
|
48
|
+
const propSchema = newSchema[key];
|
|
49
|
+
if (typeof propSchema === 'object' && propSchema !== null) {
|
|
50
|
+
// Note: Use {} instead of true to work around
|
|
51
|
+
// https://github.com/Azure/autorest/issues/3439 and
|
|
52
|
+
// https://github.com/Azure/autorest/issues/2564 (marked fixed, but fix
|
|
53
|
+
// only covers additionalProperties on top-level schemas)
|
|
54
|
+
newSchema[key] = {};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (const key of ['then', 'else']) {
|
|
59
|
+
if (newSchema[key] !== undefined) {
|
|
60
|
+
newSchema[key] = replaceAdditionalProperties(newSchema[key]);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
for (const key of ['allOf', 'anyOf', 'oneOf']) {
|
|
65
|
+
if (Array.isArray(newSchema[key])) {
|
|
66
|
+
newSchema[key] = newSchema[key].map(replaceAdditionalProperties);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return newSchema;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Does a schema describe an object with at least one property?
|
|
74
|
+
*
|
|
75
|
+
* @private
|
|
76
|
+
*/
|
|
77
|
+
function hasProperties(schema) {
|
|
78
|
+
return schema
|
|
79
|
+
&& schema.properties
|
|
80
|
+
&& Object.keys(schema.properties).length > 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Does a schema describe an object with constrained additionalProperties
|
|
84
|
+
* (or patternProperties)?
|
|
85
|
+
*
|
|
86
|
+
* @private
|
|
87
|
+
*/
|
|
88
|
+
function hasConstrainedAdditionalProps(schema) {
|
|
89
|
+
return schema
|
|
90
|
+
&& ((schema.additionalProperties
|
|
91
|
+
&& Object.keys(schema.additionalProperties).length > 0)
|
|
92
|
+
|| (schema.patternProperties
|
|
93
|
+
&& Object.keys(schema.patternProperties).length > 0));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Transformer to replace additionalProperties (and patternProperties) with an
|
|
98
|
+
* unconstrained schema alongside other properties to work around
|
|
99
|
+
* https://github.com/Azure/autorest/issues/2469
|
|
100
|
+
*/
|
|
101
|
+
export default class AdditionalPropertiesToUnconstrainedTransformer
|
|
102
|
+
extends OpenApiTransformerBase {
|
|
103
|
+
transformSchema(schema) {
|
|
104
|
+
let newSchema;
|
|
105
|
+
if (someCombinedSchema(schema, hasConstrainedAdditionalProps)
|
|
106
|
+
&& someCombinedSchema(schema, hasProperties)) {
|
|
107
|
+
newSchema = replaceAdditionalProperties(schema);
|
|
108
|
+
} else {
|
|
109
|
+
newSchema = schema;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Search for additionalProperties in child schemas
|
|
113
|
+
return super.transformSchema(newSchema);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright 2025 Kevin Locke <kevin@kevinlocke.name>
|
|
3
|
+
* @license MIT
|
|
4
|
+
* @module "openapi-transformers/any-of-null-to-nullable.js"
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
8
|
+
|
|
9
|
+
import OpenApiTransformerBase from 'openapi-transformer-base';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Transformer to convert Schema Objects with `type: 'null'` in `anyOf` (as in
|
|
13
|
+
* OAS 3.1 and JSON Schema) to `nullable: true` (as in OAS 3.0).
|
|
14
|
+
*/
|
|
15
|
+
export default class AnyOfNullToNullableTransformer
|
|
16
|
+
extends OpenApiTransformerBase {
|
|
17
|
+
transformSchema(schema) {
|
|
18
|
+
const newSchema = super.transformSchema(schema);
|
|
19
|
+
if (newSchema === null
|
|
20
|
+
|| typeof newSchema !== 'object'
|
|
21
|
+
|| Array.isArray(newSchema)) {
|
|
22
|
+
return newSchema;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const { anyOf, nullable } = newSchema;
|
|
26
|
+
if (nullable !== undefined && nullable !== true) {
|
|
27
|
+
return newSchema;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!Array.isArray(anyOf) || anyOf.length < 2) {
|
|
31
|
+
return newSchema;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const anyOfNoNull =
|
|
35
|
+
anyOf.filter((s) => !isDeepStrictEqual(s, { type: 'null' }));
|
|
36
|
+
if (anyOfNoNull.length === anyOf.length) {
|
|
37
|
+
return newSchema;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (anyOfNoNull.length === 0) {
|
|
41
|
+
return newSchema;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
...newSchema,
|
|
46
|
+
nullable: true,
|
|
47
|
+
anyOf: anyOfNoNull,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|