This repository was archived by the owner on Mar 6, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 197
/
Copy pathutil.js
250 lines (226 loc) · 7.61 KB
/
util.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
"use strict";
const debug = require("debug");
const swaggerMethods = require("@apidevtools/swagger-methods");
const format = require("util").format;
const _ = require("lodash");
/**
* Writes messages to stdout.
* Log messages are suppressed by default, but can be enabled by setting the DEBUG variable.
*
* @param {string} message - The error message. May include format strings (%s, %d, %j)
* @param {...*} [params] - One or more params to be passed to {@link util#format}
* @type {function}
*/
exports.debug = debug("swagger:middleware");
/**
* Writes messages to stderr.
* Warning messages are enabled by default, but can be suppressed by setting the WARN variable to "off".
*
* @param {Error} [err] - The error, if any
* @param {string} message - The warning message. May include format strings (%s, %d, %j)
* @param {...*} [params] - One or more params to be passed to {@link util#format}
*/
exports.warn = function (err, message, params) {
if (process.env.WARN !== "off") {
if (_.isString(err)) {
console.warn(format.apply(null, arguments));
}
else if (arguments.length > 1) {
console.warn(format.apply(null, _.drop(arguments, 1)) + " \n" + err.stack);
}
else {
console.warn(err.stack);
}
}
};
/**
* Determines whether the given value is an Express Application.
* Note: An Express Application is also an Express Router.
*
* @param {*} router
* @returns {boolean}
*/
exports.isExpressApp = function (router) {
return exports.isExpressRouter(router) &&
_.isFunction(router.get) &&
_.isFunction(router.set) &&
_.isFunction(router.enabled) &&
_.isFunction(router.disabled);
};
/**
* Determines whether the given value is an Express Router.
* Note: An Express Application is also an Express Router.
*
* @param {*} router
* @returns {boolean}
*/
exports.isExpressRouter = function (router) {
return _.isFunction(router) &&
_.isFunction(router.param);
};
/**
* Determines whether the given value is an Express routing-options object.
*
* @param {*} router
* @returns {boolean}
*/
exports.isExpressRoutingOptions = function (router) {
return _.isObject(router) &&
("caseSensitive" in router || "strict" in router || "mergeParams" in router);
};
/**
* Normalizes a path according to the given router's case-sensitivity and strict-routing settings.
*
* @param {string} path
* @param {express#Router} router
* @returns {string}
*/
exports.normalizePath = function (path, router) {
let caseSensitive, strict;
if (!path) {
return "";
}
if (exports.isExpressApp(router)) {
caseSensitive = router.enabled("case sensitive routing");
strict = router.enabled("strict routing");
}
else {
// This could be an Express Router, or a POJO
caseSensitive = !!router.caseSensitive;
strict = !!router.strict;
}
if (!caseSensitive) {
path = path.toLowerCase();
}
if (!strict && _.endsWith(path, "/")) {
path = path.substr(0, path.length - 1);
}
return path;
};
/**
* Formats a date as RFC 1123 (e.g. "Tue, 05 Nov 1994 02:09:26 GMT")
*
* @param {Date} date
* @returns {string}
*/
exports.rfc1123 = function (date) {
// jscs:disable maximumLineLength
let dayName = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][date.getUTCDay()];
let monthName = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][date.getUTCMonth()];
return [
dayName, ", ", _.padStart(date.getUTCDate(), 2, "0"), " ", monthName, " ", date.getUTCFullYear(), " ",
_.padStart(date.getUTCHours(), 2, "0"), ":", _.padStart(date.getUTCMinutes(), 2, "0"), ":", _.padStart(date.getUTCSeconds(), 2, "0"), " GMT"
].join("");
// jscs:enable maximumLineLength
};
/**
* Regular Expression that matches Swagger path params.
*/
exports.swaggerParamRegExp = /\{([^/}]+)}/g;
/**
* Determines whether the given HTTP request is a valid Swagger request.
* That is, its `req.swagger.api`, `req.swagger.path`, and `req.swagger.operation` properties are set.
*
* @param {Request} req
* @returns {boolean}
*/
exports.isSwaggerRequest = function (req) {
// If req.swagger.operation is set, then so are req.swagger.api and req.swagger.path
return req.swagger && req.swagger.operation;
};
/**
* Returns a comma-delimited list of allowed HTTP methods for the given Swagger path.
* This is useful for setting HTTP headers such as Allow and Access-Control-Allow-Methods.
*
* @param {object} path - A Path object, from the Swagger API.
* @returns {string}
*/
exports.getAllowedMethods = function (path) {
return swaggerMethods
.filter((method) => { return !!path[method]; })
.join(", ")
.toUpperCase();
};
/**
* Returns the given operation's Response objects that have HTTP response codes between
* the given min and max (inclusive).
*
* @param {object} operation - An Operation object, from the Swagger API.
* @param {integer} min - The minimum HTTP response code to include
* @param {integer} max - The maximum HTTP response code to include
*
* @returns {{code: integer, api: object}[]}
* An array of HTTP response codes and their corresponding Response objects,
* sorted by response code ("default" comes last).
*/
exports.getResponsesBetween = function (operation, min, max) {
return _.map(operation.responses,
(response, responseCode) => {
return {
code: parseInt(responseCode) || responseCode,
api: response
};
})
.sort((a, b) => {
// Sort by response code. "default" comes last.
a = _.isNumber(a.code) ? a.code : 999;
b = _.isNumber(b.code) ? b.code : 999;
return a - b;
})
.filter((response) => {
return (response.code >= min && response.code <= max) || _.isString(response.code);
});
};
/**
* Returns the combined parameters for the given path and operation.
*
* @param {object} path - A Path object, from the Swagger API
* @param {object} operation - An Operation object, from the Swagger API
* @returns {object[]} - An array of Parameter objects
*/
exports.getParameters = function (path, operation) {
let pathParams = [], operationParams = [];
// Get the path and operation parameters
if (path && path.parameters) {
pathParams = path.parameters;
}
if (operation && operation.parameters) {
operationParams = operation.parameters;
}
// Combine the path and operation parameters,
// with the operation params taking precedence over the path params
return _.uniqBy(operationParams.concat(pathParams), (param) => {
return param.name + param.in;
});
};
/**
* Gets the JSON schema for the given operation, based on its "body" or "formData" parameters.
*
* @param {object} path - A Path object, from the Swagger API
* @param {object} operation - An Operation object, from the Swagger API
* @returns {object} - A JSON schema object
*/
exports.getRequestSchema = function (path, operation) {
let params = exports.getParameters(path, operation);
// If there's a "body" parameter, then use its schema
let bodyParam = _.find(params, { in: "body" });
if (bodyParam) {
if (bodyParam.schema.type === "array") {
return bodyParam.schema.items;
}
else {
return bodyParam.schema;
}
}
else {
let schema = { type: "object", required: [], properties: {}};
// If there are "formData" parameters, then concatenate them into a single JSON schema
_.filter(params, { in: "formData" }).forEach((param) => {
schema.properties[param.name] = param;
if (param.required) {
schema.required.push(param.name);
}
});
return schema;
}
};