-
-
Notifications
You must be signed in to change notification settings - Fork 214
/
Copy pathutil.ts
137 lines (130 loc) · 4.17 KB
/
util.ts
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
import type { ErrorObject } from 'ajv-draft-04';
import { Request } from 'express';
import { ValidationError } from '../framework/types';
export class ContentType {
public readonly contentType: string = null;
public readonly mediaType: string = null;
public readonly charSet: string = null;
public readonly withoutBoundary: string = null;
public readonly isWildCard: boolean;
private constructor(contentType: string | null) {
this.contentType = contentType;
if (contentType) {
this.withoutBoundary = contentType
.replace(/;\s{0,}boundary.*/, '')
.toLowerCase();
this.mediaType = this.withoutBoundary.split(';')[0].toLowerCase().trim();
this.charSet = this.withoutBoundary.split(';')[1]?.toLowerCase();
this.isWildCard = RegExp(/^[a-z]+\/\*$/).test(this.contentType);
if (this.charSet) {
this.charSet = this.charSet.toLowerCase().trim();
}
}
}
public static from(req: Request): ContentType {
return new ContentType(req.headers['content-type']);
}
public static fromString(type: string): ContentType {
return new ContentType(type);
}
public equivalents(): string[] {
if (!this.withoutBoundary) return [];
if (this.charSet) {
return [this.mediaType, `${this.mediaType}; ${this.charSet}`];
}
return [this.withoutBoundary, `${this.mediaType}; charset=utf-8`];
}
}
/**
* (side-effecting) modifies the errors object
* TODO - do this some other way
* @param errors
*/
export function augmentAjvErrors(errors: ErrorObject[] = []): ErrorObject[] {
errors.forEach((e) => {
if (e.keyword === 'enum') {
const params: any = e.params;
const allowedEnumValues = params?.allowedValues;
e.message = !!allowedEnumValues
? `${e.message}: ${allowedEnumValues.join(', ')}`
: e.message;
}
});
const serDesPaths = new Set<string>();
return errors.filter((e) => {
if (serDesPaths.has(e.schemaPath)) {
return false;
}
if (e.params['x-eov-res-serdes']) {
// If response serialization failed,
// silence additional errors about not being a string.
serDesPaths.add(e.schemaPath.replace('x-eov-res-serdes', 'x-eov-type'));
}
return true;
});
}
export function ajvErrorsToValidatorError(
status: number,
errors: ErrorObject[],
): ValidationError {
return {
status,
errors: errors.map((e) => {
const params: any = e.params;
const required =
params?.missingProperty &&
e.instancePath + '/' + params.missingProperty;
const additionalProperty =
params?.additionalProperty &&
e.instancePath + '/' + params.additionalProperty;
const path =
required ?? additionalProperty ?? e.instancePath ?? e.schemaPath;
return {
path,
message: e.message,
errorCode: `${e.keyword}.openapi.validation`,
};
}),
};
}
export const deprecationWarning =
process.env.NODE_ENV !== 'production' ? console.warn : () => {};
/**
*
* @param accepts the list of accepted media types
* @param expectedTypes - expected media types defined in the response schema
* @returns the content-type
*/
export const findResponseContent = function (
accepts: string[],
expectedTypes: string[],
): string {
const expectedTypesSet = new Set(expectedTypes);
// if accepts are supplied, try to find a match, and use its validator
for (const accept of accepts) {
const act = ContentType.fromString(accept);
if (act.contentType === '*/*') {
return expectedTypes[0];
} else if (expectedTypesSet.has(act.contentType)) {
return act.contentType;
} else if (expectedTypesSet.has(act.mediaType)) {
return act.mediaType;
} else if (act.isWildCard) {
// wildcard of type application/*
const [type] = act.contentType.split('/', 1);
for (const expectedType of expectedTypesSet) {
if (new RegExp(`^${type}\/.+$`).test(expectedType)) {
return expectedType;
}
}
} else {
for (const expectedType of expectedTypes) {
const ect = ContentType.fromString(expectedType);
if (ect.mediaType === act.mediaType) {
return expectedType;
}
}
}
}
return null;
};