-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinline-non-object-schemas.js
120 lines (104 loc) · 3.85 KB
/
inline-non-object-schemas.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
/**
* @copyright Copyright 2020 Kevin Locke <kevin@kevinlocke.name>
* @license MIT
* @module "openapi-transformers/inline-non-object-schemas.js"
*/
import { debuglog } from 'node:util';
import { JsonPointer } from 'json-ptr';
import OpenApiTransformerBase from 'openapi-transformer-base';
const debug = debuglog('inline-non-object-schemas');
const inlineAllSymbol = Symbol('inlineAll');
const resolveRefSymbol = Symbol('resolveRef');
// JSON Schema validation keywords supported by Autorest which must be inlined
// https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/mgmtcommon/ClientRuntime/ClientRuntime/ValidationRules.cs
// Note: exclusiveMaximum/Minimum only modify maximum/minimum validation.
const validationKeywords = {
maxItems: true,
maxLength: true,
maximum: true,
minItems: true,
minLength: true,
minimum: true,
multipleOf: true,
pattern: true,
uniqueItems: true,
};
/**
* Transformer to inline schemas with non-object type so that Autorest will
* generate validation code.
*
* https://github.com/Azure/autorest.csharp/issues/795
*/
export default class InlineNonObjectSchemaTransformer
extends OpenApiTransformerBase {
constructor({ inlineAll, resolveRef } = {}) {
super();
if (resolveRef !== undefined && typeof resolveRef !== 'function') {
throw new TypeError('resolveRef must be a function');
}
this[inlineAllSymbol] = Boolean(inlineAll);
this[resolveRefSymbol] = resolveRef;
}
transformSchema(schema) {
const { $ref, ...nonRef } = schema;
if (typeof $ref !== 'string') {
return super.transformSchema(schema);
}
const refSchema = this[resolveRefSymbol]($ref);
if (refSchema === undefined) {
debug('Unable to resolve $ref %s', $ref);
return super.transformSchema(schema);
}
if (!refSchema || !refSchema.type || refSchema.type === 'object') {
debug('Not inlining %s: type %s', $ref, refSchema && refSchema.type);
return super.transformSchema(schema);
}
if (refSchema.enum) {
debug('Not inlining %s: enum', $ref);
return super.transformSchema(schema);
}
if (!this[inlineAllSymbol]
&& !Object.keys(refSchema).some((prop) => validationKeywords[prop])
// exclusiveMaximum/exclusiveMinimum are numbers in JSON Schema
// Draft 2020-12 referenced by OAS 3.1.0 and apply on their own:
// https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-validation-00#section-6.2.3
// exclusiveMaximum/exclusiveMinimum are boolean in JSON Schema Write 00
// referenced by OAS 3.0:
// https://datatracker.ietf.org/doc/html/draft-wright-json-schema-validation-00#section-5.3
// and JSON Schema Draft 4 referenced by OAS 2:
// https://datatracker.ietf.org/doc/html/draft-fge-json-schema-validation-00#section-5.1.2
// which only affect minimum/maximum and have no effect on their own.
&& typeof refSchema.exclusiveMaximum !== 'number'
&& typeof refSchema.exclusiveMinimum !== 'number') {
debug(
'Not inlining %s: No validation keywords require inlining',
$ref,
);
return super.transformSchema(schema);
}
debug('Inlining %s.', $ref);
return {
...super.transformSchema(refSchema),
// Like Autorest, allow properties other than $ref
...nonRef,
};
}
transformOpenApi(openapi) {
// If resolveRefSymbol was not set from options, resolve against OpenAPI
// Object being transformed.
const optResolve = this[resolveRefSymbol];
if (!optResolve) {
this[resolveRefSymbol] = function resolveRef($ref) {
// JsonPointer.get would throw for non-local refs
return $ref[0] === '#' ? JsonPointer.get(openapi, $ref) : undefined;
};
}
try {
return super.transformOpenApi(openapi);
} finally {
if (optResolve) {
this[resolveRefSymbol] = optResolve;
}
}
}
}