@loopback/rest
Version:
Expose controllers as REST endpoints and route REST API requests to controller methods
103 lines (96 loc) • 3.17 kB
text/typescript
// Copyright IBM Corp. and LoopBack contributors 2020. All Rights Reserved.
// Node module: @loopback/rest
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
import {
ApplicationMetadata,
BindingScope,
CoreBindings,
inject,
injectable,
JSONObject,
JSONValue,
} from '@loopback/core';
import {
asSpecEnhancer,
ContactObject,
DEFAULT_OPENAPI_SPEC_INFO,
mergeOpenAPISpec,
OASEnhancer,
OpenApiSpec,
} from '@loopback/openapi-v3';
import debugFactory from 'debug';
const debug = debugFactory('loopback:openapi:spec-enhancer:info');
/**
* An OpenAPI spec enhancer to populate `info` with application metadata
* (package.json).
*/
(asSpecEnhancer, {scope: BindingScope.SINGLETON})
export class InfoSpecEnhancer implements OASEnhancer {
name = 'info';
constructor(
true})
readonly pkg?: ApplicationMetadata,
) {}
(CoreBindings.APPLICATION_METADATA, {optional: modifySpec(spec: OpenApiSpec): OpenApiSpec {
if (this.pkg == null) {
debug('Application metadata is not found. Skipping spec enhancing.');
return spec;
}
const contact: ContactObject = InfoSpecEnhancer.parseAuthor(
this.pkg.author,
);
// Only override `info` if the `spec.info` is not customized
const overrideInfo =
spec.info.title === DEFAULT_OPENAPI_SPEC_INFO.title &&
spec.info.version === DEFAULT_OPENAPI_SPEC_INFO.version;
const patchSpec = {
info: {
title: overrideInfo ? this.pkg.name : spec.info.title ?? this.pkg.name,
description: overrideInfo
? this.pkg.description
: spec.info.description ?? this.pkg.description,
version: overrideInfo
? this.pkg.version
: spec.info.version ?? this.pkg.version,
contact: overrideInfo ? contact : spec.info.contact ?? contact,
},
};
debug('Enhancing OpenAPI spec with %j', patchSpec);
return mergeOpenAPISpec(spec, patchSpec);
}
/**
* Parse package.json
* {@link https://docs.npmjs.com/files/package.json#people-fields-author-contributors | author}
*
* @param author - Author string or object from package.json
*/
private static parseAuthor(author: JSONValue) {
let contact: ContactObject = {};
if (author == null) {
contact = {};
} else if (typeof author === 'string') {
// "Barney Rubble <b@rubble.com> (http://barnyrubble.tumblr.com/)"
const emailRegex = /<([^<>]+)>/; // <email>
const urlRegex = /\(([^()]+)\)/; // (url)
const nameRegex = /([^<>()]+)/;
contact = {
name: nameRegex.exec(author)?.[1]?.trim(),
email: emailRegex.exec(author)?.[1]?.trim(),
url: urlRegex.exec(author)?.[1]?.trim(),
};
} else if (typeof author === 'object') {
const authorObj = author as JSONObject;
contact = {
name: authorObj.name as string,
email: authorObj.email as string,
url: authorObj.url as string,
};
}
// Remove undefined/null values
for (const p in contact) {
if (contact[p] == null) delete contact[p];
}
return contact;
}
}