@elemental-concept/grappa
Version:
Decorator-powered REST client for Angular and its HttpClient
288 lines (268 loc) • 11.6 kB
JavaScript
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