Skip to content

Commit

Permalink
ts3.7 optional chaining / nullish coalescing updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Carmine DiMascio committed Nov 9, 2019
1 parent bba06b2 commit d051acf
Show file tree
Hide file tree
Showing 20 changed files with 55 additions and 79 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ dist
/coverage
.coveralls.yml
.nyc_output
secrets.zip
secrets.zip
jest
junk
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ new OpenApiValidator({
```javascript
app.use((err, req, res, next) => {
// format error
res.status(err.status || 500).json({
res.status(err.status ?? 500).json({
message: err.message,
errors: err.errors,
});
Expand Down Expand Up @@ -138,7 +138,7 @@ app.post('/v1/pets/:id/photos', function(req, res, next) {
// 6. Create an Express error handler
app.use((err, req, res, next) => {
// 7. Customize errors
res.status(err.status || 500).json({
res.status(err.status ?? 500).json({
message: err.message,
errors: err.errors,
});
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@
"supertest": "^4.0.2",
"ts-node": "^8.3.0",
"tsc": "^1.20150623.0",
"typescript": "^3.6.4"
"typescript": "^3.7.2"
}
}
2 changes: 1 addition & 1 deletion src/framework/base.path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default class BasePath {
for (const variable in server.variables) {
if (server.variables.hasOwnProperty(variable)) {
const v = server.variables[variable];
const enums = v.enum || [];
const enums = v.enum ?? [];
if (enums.length === 0 && v.default) enums.push(v.default);

this.variables[variable] = {
Expand Down
2 changes: 1 addition & 1 deletion src/framework/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default class OpenAPIFramework implements IOpenAPIFramework {
? getBasePathsFromServers(this.apiDoc.servers)
: [
new BasePath({
url: (this.apiDoc.basePath || '').replace(/\/$/, ''),
url: (this.apiDoc.basePath ?? '').replace(/\/$/, ''),
}),
];

Expand Down
2 changes: 1 addition & 1 deletion src/framework/openapi.schema.validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class OpenAPISchemaValidator {
if (!ver) throw Error('version missing from OpenAPI specification');
if (ver != 3) throw Error('OpenAPI v3 specification version is required');

const schema = merge({}, openapi3Schema, extensions || {});
const schema = merge({}, openapi3Schema, extensions ?? {});
v.addSchema(schema);
this.validator = v.compile(schema);
}
Expand Down
8 changes: 4 additions & 4 deletions src/framework/openapi.spec.loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export class OpenApiSpecLoader {

load() {
const framework = this.createFramework(this.opts);
const apiDoc = framework.apiDoc || {};
const bps = framework.basePaths || [];
const apiDoc = framework.apiDoc ?? {};
const bps = framework.basePaths ?? [];
const basePaths = bps.reduce((acc, bp) => {
bp.all().forEach(path => acc.add(path));
return acc;
Expand Down Expand Up @@ -52,10 +52,10 @@ export class OpenApiSpecLoader {
continue;
}
const schemaParameters = new Set();
(schema.parameters || []).forEach(parameter =>
(schema.parameters ?? []).forEach(parameter =>
schemaParameters.add(parameter),
);
((methods as any).parameters || []).forEach(parameter =>
((methods as any).parameters ?? []).forEach(parameter =>
schemaParameters.add(parameter),
);
schema.parameters = Array.from(schemaParameters);
Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class OpenApiValidator {
this.installMultipartMiddleware();

const components = this.context.apiDoc.components;
if (components && components.securitySchemes) {
if (components?.securitySchemes) {
this.installSecurityMiddleware();
}

Expand Down Expand Up @@ -76,7 +76,7 @@ export class OpenApiValidator {
) => {
if (req.openapi.pathParams) {
// override path params
req.params[name] = req.openapi.pathParams[name] || req.params[name];
req.params[name] = req.openapi.pathParams[name] ?? req.params[name];
}
next();
},
Expand Down
10 changes: 2 additions & 8 deletions src/middlewares/openapi.multipart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,7 @@ function isValidContentType(req: Request): boolean {
}

function isMultipart(req: OpenApiRequest): boolean {
return (
req.openapi &&
req.openapi.schema &&
req.openapi.schema.requestBody &&
req.openapi.schema.requestBody.content &&
req.openapi.schema.requestBody.content['multipart/form-data']
);
return req?.openapi?.schema?.requestBody?.content?.['multipart/form-data'];
}

function error(req: OpenApiRequest, err: Error) {
Expand All @@ -67,7 +61,7 @@ function error(req: OpenApiRequest, err: Error) {
// HACK
// TODO improve multer error handling
const missingField = /Multipart: Boundary not found/i.test(
err.message || '',
err.message ?? '',
);
if (missingField) {
return validationError(400, req.path, 'multipart file(s) required');
Expand Down
35 changes: 13 additions & 22 deletions src/middlewares/openapi.request.validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class RequestValidator {

// cache middleware by combining method, path, and contentType
// TODO contentType could have value not_provided
const contentType = extractContentType(req) || 'not_provided';
const contentType = extractContentType(req) ?? 'not_provided';
const key = `${req.method}-${req.path}-${contentType}`;

if (!this._middlewareCache[key]) {
Expand All @@ -71,13 +71,13 @@ export class RequestValidator {

let requestBody = pathSchema.requestBody;

if (requestBody && requestBody.hasOwnProperty('$ref')) {
if (requestBody?.hasOwnProperty('$ref')) {
const id = requestBody.$ref.replace(/^.+\//i, '');
requestBody = this._apiDocs.components.requestBodies[id];
}

let body = this.requestBodyToSchema(path, contentType, requestBody);
let requiredAdds = requestBody && requestBody.required ? ['body'] : [];
let requiredAdds = requestBody?.required ? ['body'] : [];

const schema = {
// $schema: "http://json-schema.org/draft-04/schema#",
Expand All @@ -100,7 +100,7 @@ export class RequestValidator {
Object.keys(req.openapi.pathParams).length > 0;

if (shouldUpdatePathParams) {
req.params = req.openapi.pathParams || req.params;
req.params = req.openapi.pathParams ?? req.params;
}

req.schema = schema;
Expand All @@ -111,7 +111,7 @@ export class RequestValidator {
* https://swagger.io/docs/specification/describing-parameters/#schema-vs-content
*/
parameters.parseJson.forEach(item => {
if (req[item.reqField] && req[item.reqField][item.name]) {
if (req[item.reqField]?.[item.name]) {
req[item.reqField][item.name] = JSON.parse(
req[item.reqField][item.name],
);
Expand All @@ -125,7 +125,7 @@ export class RequestValidator {
* filter=foo%20bar%20baz
*/
parameters.parseArray.forEach(item => {
if (req[item.reqField] && req[item.reqField][item.name]) {
if (req[item.reqField]?.[item.name]) {
req[item.reqField][item.name] = req[item.reqField][item.name].split(
item.delimiter,
);
Expand All @@ -137,8 +137,7 @@ export class RequestValidator {
*/
parameters.parseArrayExplode.forEach(item => {
if (
req[item.reqField] &&
req[item.reqField][item.name] &&
req[item.reqField]?.[item.name] &&
!(req[item.reqField][item.name] instanceof Array)
) {
req[item.reqField][item.name] = [req[item.reqField][item.name]];
Expand All @@ -156,7 +155,7 @@ export class RequestValidator {
next();
} else {
// TODO look into Ajv async errors plugins
const errors = augmentAjvErrors([...(validator.errors || [])]);
const errors = augmentAjvErrors([...(validator.errors ?? [])]);
const err = ajvErrorsToValidatorError(400, errors);
const message = this.ajv.errorsText(errors, { dataVar: 'request' });
throw ono(err, message);
Expand Down Expand Up @@ -190,7 +189,7 @@ export class RequestValidator {
: `unsupported media type ${contentType}`;
throw validationError(415, path, msg);
}
return content.schema || {};
return content.schema ?? {};
}
return {};
}
Expand All @@ -203,7 +202,7 @@ export class RequestValidator {
const securityKey = Object.keys(sec)[0];
return securitySchema[securityKey];
})
.filter(sec => sec && sec.in && sec.in === 'query')
.filter(sec => sec?.in === 'query')
.map(sec => sec.name)
: [];
}
Expand Down Expand Up @@ -242,7 +241,7 @@ export class RequestValidator {
}

let parameterSchema = parameter.schema;
if (parameter.content && parameter.content[TYPE_JSON]) {
if (parameter.content?.[TYPE_JSON]) {
parameterSchema = parameter.content[TYPE_JSON].schema;
parseJson.push({ name, reqField });
}
Expand All @@ -252,11 +251,7 @@ export class RequestValidator {
throw validationError(400, path, message);
}

if (
parameter.schema &&
parameter.schema.type === 'array' &&
!parameter.explode
) {
if (parameter.schema?.type === 'array' && !parameter.explode) {
const delimiter = arrayDelimiter[parameter.style];
if (!delimiter) {
const message = `Parameter 'style' has incorrect value '${parameter.style}' for [${parameter.name}]`;
Expand All @@ -265,11 +260,7 @@ export class RequestValidator {
parseArray.push({ name, reqField, delimiter });
}

if (
parameter.schema &&
parameter.schema.type === 'array' &&
parameter.explode
) {
if (parameter.schema?.type === 'array' && parameter.explode) {
parseArrayExplode.push({ name, reqField });
}

Expand Down
11 changes: 4 additions & 7 deletions src/middlewares/openapi.response.validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class ResponseValidator {
public validate() {
return mung.json((body, req: any, res) => {
if (req.openapi) {
const responses = req.openapi.schema && req.openapi.schema.responses;
const responses = req.openapi.schema?.responses;
const validators = this._getOrBuildValidator(req, responses);
const statusCode = res.statusCode;
const path = req.path;
Expand All @@ -45,7 +45,7 @@ export class ResponseValidator {
return this.buildValidators(responses);
}

const contentType = extractContentType(req) || 'not_provided';
const contentType = extractContentType(req) ?? 'not_provided';
const key = `${req.method}-${req.path}-${contentType}`;

let validators = this.validatorsCache[key];
Expand Down Expand Up @@ -100,10 +100,7 @@ export class ResponseValidator {
* @returns a map of validators
*/
private buildValidators(responses) {
const canValidate = r =>
typeof r.content === 'object' &&
r.content[TYPE_JSON] &&
r.content[TYPE_JSON].schema;
const canValidate = r => typeof r.content === 'object' && r.content[TYPE_JSON]?.schema;

const schemas = {};
for (const entry of <any[]>Object.entries(responses)) {
Expand All @@ -122,7 +119,7 @@ export class ResponseValidator {
properties: {
response: schema,
},
components: this.spec.components || {},
components: this.spec.components ?? {},
};
}

Expand Down
10 changes: 4 additions & 6 deletions src/middlewares/openapi.security.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function security(

// use the local security object or fallbac to api doc's security or undefined
const securities: OpenAPIV3.SecurityRequirementObject[] =
req.openapi.schema.security || context.apiDoc.security;
req.openapi.schema.security ?? context.apiDoc.security;

const path: string = req.openapi.openApiRoute;

Expand Down Expand Up @@ -84,7 +84,7 @@ export function security(
if (success) next();
else throw firstError;
} catch (e) {
const message = (e && e.error && e.error.message) || 'unauthorized';
const message = e?.error?.message || 'unauthorized';
const err = validationError(e.status, path, message);
next(err);
}
Expand Down Expand Up @@ -117,9 +117,7 @@ class SecuritySchemes {
}
const securityKey = Object.keys(s)[0];
const scheme: any = this.securitySchemes[securityKey];
const handler =
(this.securityHandlers && this.securityHandlers[securityKey]) ||
fallbackHandler;
const handler = this.securityHandlers?.[securityKey] ?? fallbackHandler;
const scopesTmp = s[securityKey];
const scopes = Array.isArray(scopesTmp) ? scopesTmp : [];

Expand Down Expand Up @@ -154,7 +152,7 @@ class SecuritySchemes {
} catch (e) {
return {
success: false,
status: e.status || 401,
status: e.status ?? 401,
error: e,
};
}
Expand Down
16 changes: 5 additions & 11 deletions src/middlewares/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const _validationError = (
{
path,
message,
...({ errors } || {}),
...({ errors } ?? {}),
},
],
});
Expand All @@ -52,7 +52,7 @@ export function augmentAjvErrors(
errors.forEach(e => {
if (e.keyword === 'enum') {
const params: any = e.params;
const allowedEnumValues = params && params.allowedValues;
const allowedEnumValues = params?.allowedValues;
e.message = !!allowedEnumValues
? `${e.message}: ${allowedEnumValues.join(', ')}`
: e.message;
Expand All @@ -68,15 +68,9 @@ export function ajvErrorsToValidatorError(
status,
errors: errors.map(e => {
const params: any = e.params;
const required =
params &&
params.missingProperty &&
e.dataPath + '.' + params.missingProperty;
const additionalProperty =
params &&
params.additionalProperty &&
e.dataPath + '.' + params.additionalProperty;
const path = required || additionalProperty || e.dataPath || e.schemaPath;
const required = params?.missingProperty && e.dataPath + '.' + params.missingProperty;
const additionalProperty = params?.additionalProperty && e.dataPath + '.' + params.additionalProperty;
const path = required ?? additionalProperty ?? e.dataPath ?? e.schemaPath;
return {
path,
message: e.message,
Expand Down
2 changes: 1 addition & 1 deletion test/common/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export async function createApp(
if (useRoutes) {
// Register error handler
app.use((err, req, res, next) => {
res.status(err.status || 500).json({
res.status(err.status ?? 500).json({
message: err.message,
errors: err.errors,
});
Expand Down
Loading

0 comments on commit d051acf

Please sign in to comment.