UNPKG

@elemental-concept/grappa

Version:

Decorator-powered REST client for Angular and its HttpClient

288 lines (268 loc) 11.6 kB
import * as i0 from '@angular/core'; import { Injectable, NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import * as i1 from '@angular/common/http'; import { HttpClientModule } from '@angular/common/http'; class ClassDescriptor { constructor(uid, proto) { this.uid = uid; this.proto = proto; this.methods = {}; this.customMetadata = {}; this.filtersBefore = []; this.filtersAfter = []; } } class MethodDescriptor { constructor(name) { this.name = name; } } var ObserveOptions; (function (ObserveOptions) { ObserveOptions["Body"] = "body"; ObserveOptions["Response"] = "response"; ObserveOptions["Events"] = "events"; })(ObserveOptions || (ObserveOptions = {})); const uidKey = '__GRAPPA_UID'; let generator = 0; function UID(o) { if (o[uidKey] === undefined) { Object.defineProperty(o, uidKey, { value: ++generator, enumerable: false, writable: false }); } return o[uidKey]; } const instances = { restClientInstance: null }; class RegistryImpl { constructor() { this.classes = {}; this.registerRequest = (method, endpoint, proto, property, options) => { const classDescriptor = this.getClassDescriptor(proto); const methodDescriptor = new MethodDescriptor(property); methodDescriptor.method = method; methodDescriptor.endpoint = endpoint; methodDescriptor.options = Object.assign({}, RegistryImpl.defaultRequestOptions, options); classDescriptor.methods[property] = methodDescriptor; proto[property] = prepareRequest(classDescriptor, property); }; this.registerClass = (baseUrl, constructor) => { const classDescriptor = this.getClassDescriptor(constructor.prototype); classDescriptor.ctor = constructor; classDescriptor.baseUrl = baseUrl; }; this.getCustomMetadata = (proto, method, customKey) => { const classDescriptor = this.getClassDescriptor(proto); return this.getCustomMetadataImpl(classDescriptor, method, customKey); }; this.registerBeforeFilter = (proto, method, applyTo) => this.getClassDescriptor(proto).filtersBefore.push({ filterFunction: method, applyTo }); this.registerAfterFilter = (proto, method, applyTo) => this.getClassDescriptor(proto).filtersAfter.push({ filterFunction: method, applyTo }); this.getClassDescriptor = (proto) => { const uid = UID(proto); let classDescriptor = this.classes[uid]; if (classDescriptor === undefined) { classDescriptor = new ClassDescriptor(uid, proto); this.classes[uid] = classDescriptor; } return classDescriptor; }; // used for Grappa-Cache this.registerAlternativeHttpClient = (proto, client) => this.getClassDescriptor(proto).restClient = client; // used for Grappa-Cache this.putCustomMetadata = (proto, method, customKey, data) => { const classDescriptor = this.getClassDescriptor(proto); if (!classDescriptor.customMetadata.hasOwnProperty(method)) { classDescriptor.customMetadata[method] = {}; } classDescriptor.customMetadata[method][customKey] = data; }; // used for Grappa-Cache this.getCustomMetadataForDescriptor = (classDescriptor, method, customKey) => this.getCustomMetadataImpl(classDescriptor, method.name, customKey); this.getCustomMetadataImpl = (classDescriptor, methodNAme, customKey) => classDescriptor.customMetadata.hasOwnProperty(methodNAme) && classDescriptor.customMetadata[methodNAme].hasOwnProperty(customKey) ? classDescriptor.customMetadata[methodNAme][customKey] : null; } static { this.defaultRequestOptions = { observe: ObserveOptions.Body }; } get defaultClient() { return instances.restClientInstance; } } function prepareRequest(classDescriptor, property) { // eslint-disable-next-line space-before-function-paren return function (...args) { if (!classDescriptor.methods.hasOwnProperty(property)) { throw new ReferenceError(`REST function "${property}" is not defined for ${classDescriptor.ctor.name}.`); } const method = classDescriptor.methods[property]; const request = { baseUrl: classDescriptor.baseUrl, endpoint: method.endpoint, method: method.method, args, headers: {}, emptyBody: false, classDescriptor, methodDescriptor: method, reportProgress: method.options.reportProgress }; if (method.options.hasOwnProperty('query')) { const idx = typeof method.options.query === 'number' ? method.options.query : args.length - 1; if (idx >= 0 && idx < args.length) { request.params = args[idx]; } } if (method.options.hasOwnProperty('emptyBody')) { request.emptyBody = true; } for (const filter of classDescriptor.filtersBefore) { if (isApplicable(filter, property)) { filter.filterFunction.call(this, request); } } const restClient = classDescriptor.restClient instanceof Object ? classDescriptor.restClient : instances.restClientInstance; let response = restClient.request(request, method.options.observe); for (const filter of classDescriptor.filtersAfter) { if (isApplicable(filter, property)) { response = filter.filterFunction.call(this, response); } } return response; }; } function isApplicable(filter, property) { if (filter.applyTo === null) { return true; } const nameList = typeof filter.applyTo === 'string' ? [filter.applyTo] : filter.applyTo; return nameList.indexOf(property) >= 0; } const Registry = new RegistryImpl(); function AfterRequest(applyTo = null) { return (target, propertyKey, descriptor) => { Registry.registerAfterFilter(target, descriptor.value, applyTo); }; } function BeforeRequest(applyTo = null) { return (target, propertyKey, descriptor) => { Registry.registerBeforeFilter(target, descriptor.value, applyTo); }; } function DELETE(endpoint, options = {}) { return (target, property) => { Registry.registerRequest('DELETE', endpoint, target, property, options); }; } function GET(endpoint, options = {}) { return (target, property) => { Registry.registerRequest('GET', endpoint, target, property, options); }; } function PATCH(endpoint, options = {}) { return (target, property) => { Registry.registerRequest('PATCH', endpoint, target, property, options); }; } function POST(endpoint, options = {}) { return (target, property) => { Registry.registerRequest('POST', endpoint, target, property, options); }; } function PUT(endpoint, options = {}) { return (target, property) => { Registry.registerRequest('PUT', endpoint, target, property, options); }; } function RestClient(baseUrl = '') { return (constructor) => { Registry.registerClass(baseUrl, constructor); }; } // @dynamic class UrlParser { static { this.SlashSuffix = /[\\/]*$/; } static { this.SlashPrefix = /^[\\/]*/; } static { this.Placeholder = /{([0-9]+)}/g; } static { this.parse = (baseUrl, endpoint, args) => UrlParser .merge(baseUrl, endpoint) .replace(UrlParser.Placeholder, (match, index) => UrlParser.replace(index, args)); } static { this.replace = (index, args) => { const idx = parseInt(index, 10); if (idx < 0 || idx >= args.length) { throw new ReferenceError(`REST method was not provided with argument at index ${idx}.`); } return encodeURIComponent(args[idx]); }; } static { this.merge = (baseUrl, endpoint) => { if (typeof baseUrl === 'string' && baseUrl.length > 0) { return `${baseUrl.replace(UrlParser.SlashSuffix, '')}/${endpoint.replace(UrlParser.SlashPrefix, '')}`; } return endpoint; }; } } class RestClientService { constructor(http) { this.http = http; this.request = (request, observe) => { const method = request.method.toUpperCase(); const baseUrl = this.getBaseUrl(request); const body = this.getBody(request, method); return this.http .request(method, UrlParser.parse(baseUrl, request.endpoint, request.args), { body, headers: request.headers, params: request.params, observe: request.reportProgress ? 'events' : observe, responseType: 'json', reportProgress: request.reportProgress }); }; this.getBaseUrl = (request) => typeof request.baseUrl === 'function' ? request.baseUrl() : request.baseUrl; this.getBody = (request, method) => { if (method === 'PATCH' || method === 'POST' || method === 'PUT') { return request.emptyBody ? null : request.args.length > 0 ? request.args[request.args.length - 1] : undefined; } return null; }; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.8", ngImport: i0, type: RestClientService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.8", ngImport: i0, type: RestClientService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.8", ngImport: i0, type: RestClientService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i1.HttpClient }] }); class GrappaModule { constructor(restClient) { instances.restClientInstance = restClient; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.8", ngImport: i0, type: GrappaModule, deps: [{ token: RestClientService }], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.0.8", ngImport: i0, type: GrappaModule, imports: [CommonModule, HttpClientModule] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.0.8", ngImport: i0, type: GrappaModule, imports: [CommonModule, HttpClientModule] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.8", ngImport: i0, type: GrappaModule, decorators: [{ type: NgModule, args: [{ declarations: [], imports: [CommonModule, HttpClientModule], exports: [] }] }], ctorParameters: () => [{ type: RestClientService }] }); /** * Generated bundle index. Do not edit. */ export { AfterRequest, BeforeRequest, ClassDescriptor, DELETE, GET, GrappaModule, MethodDescriptor, ObserveOptions, PATCH, POST, PUT, Registry, RestClient, UrlParser }; //# sourceMappingURL=elemental-concept-grappa.mjs.map