-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathadditional-properties-to-unconstrained.js
115 lines (100 loc) · 3.15 KB
/
additional-properties-to-unconstrained.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
/**
* @copyright Copyright 2019-2020 Kevin Locke <kevin@kevinlocke.name>
* @license MIT
* @module "openapi-transformers/additional-properties-to-unconstrained.js"
*/
import OpenApiTransformerBase from 'openapi-transformer-base';
/** Applies a predicate to each schema which contributes to the generated
* type of a given schema.
*
* @private
*/
function someCombinedSchema(schema, predicate) {
if (predicate(schema)) {
return true;
}
if (typeof schema !== 'object' || schema === null) {
return false;
}
if (['then', 'else'].some(
(key) => someCombinedSchema(schema[key], predicate),
)) {
return true;
}
return ['allOf', 'anyOf', 'oneOf'].some(
(key) => Array.isArray(schema[key])
&& schema[key].some((s) => someCombinedSchema(s, predicate)),
);
}
/** Replaces additionalProperties (and patternProperties) in each schema which
* contributes to the generated type of a given schema.
*
* @private
*/
function replaceAdditionalProperties(schema) {
if (typeof schema !== 'object' || schema === null) {
return schema;
}
const newSchema = { ...schema };
for (const key of ['additionalProperties', 'patternProperties']) {
const propSchema = newSchema[key];
if (typeof propSchema === 'object' && propSchema !== null) {
// Note: Use {} instead of true to work around
// https://github.com/Azure/autorest/issues/3439 and
// https://github.com/Azure/autorest/issues/2564 (marked fixed, but fix
// only covers additionalProperties on top-level schemas)
newSchema[key] = {};
}
}
for (const key of ['then', 'else']) {
if (newSchema[key] !== undefined) {
newSchema[key] = replaceAdditionalProperties(newSchema[key]);
}
}
for (const key of ['allOf', 'anyOf', 'oneOf']) {
if (Array.isArray(newSchema[key])) {
newSchema[key] = newSchema[key].map(replaceAdditionalProperties);
}
}
return newSchema;
}
/** Does a schema describe an object with at least one property?
*
* @private
*/
function hasProperties(schema) {
return schema
&& schema.properties
&& Object.keys(schema.properties).length > 0;
}
/** Does a schema describe an object with constrained additionalProperties
* (or patternProperties)?
*
* @private
*/
function hasConstrainedAdditionalProps(schema) {
return schema
&& ((schema.additionalProperties
&& Object.keys(schema.additionalProperties).length > 0)
|| (schema.patternProperties
&& Object.keys(schema.patternProperties).length > 0));
}
/**
* Transformer to replace additionalProperties (and patternProperties) with an
* unconstrained schema alongside other properties to work around
* https://github.com/Azure/autorest/issues/2469
*/
export default class AdditionalPropertiesToUnconstrainedTransformer
extends OpenApiTransformerBase {
transformSchema(schema) {
let newSchema;
if (someCombinedSchema(schema, hasConstrainedAdditionalProps)
&& someCombinedSchema(schema, hasProperties)) {
newSchema = replaceAdditionalProperties(schema);
} else {
newSchema = schema;
}
// Search for additionalProperties in child schemas
return super.transformSchema(newSchema);
}
}