Adding Rsx and decorator

This commit is contained in:
Martin Karkowski 2020-08-21 16:49:48 +02:00
parent d18601132e
commit 9b6788b47b
9 changed files with 293 additions and 24 deletions

View File

@ -432,7 +432,7 @@ const sharedMethods = injectedClasses[0].getMethods()
const parsedMethods = sharedMethods.map(methodObject => getMethodInfo(methodObject.declaration as MethodDeclaration)); const parsedMethods = sharedMethods.map(methodObject => getMethodInfo(methodObject.declaration as MethodDeclaration));
// Get the Properties // Get the Properties
const sharedObservables = getMatchingProperties(injectedClasses[0], 'IObservable', false) const sharedObservables = getMatchingProperties(injectedClasses[0], 'NopeObersvable', false)
.filter(property => .filter(property =>
property.isPublic && property.isPublic &&
getDecorators(property.declaration, 'inject', importMapping.aliasToOriginal, false, false) getDecorators(property.declaration, 'inject', importMapping.aliasToOriginal, false, false)

88
lib/decorators.ts Normal file
View File

@ -0,0 +1,88 @@
// Symbols for the Property Registery:
const _registedMethods_ = Symbol('_registedMethods_');
const _registedParams_ = Symbol('_registedParams_');
// Interfaces for the Class
export interface IExportApiParameters {
url: string,
}
export interface IExportMethodParameters {
url?: string,
}
export interface IExportPropertyParameters {
url?: string,
readonly?: boolean
}
export const unicorn = {
test: []
}
/**
* Decorator used to export a Class API over openAPI
* @param options
*/
export function eportApi(options: IExportApiParameters) {
return function <T extends { new(...args: any[]): {} }>(Base: T) {
return class extends Base {
constructor(...args: any[]) {
super(...args);
// Adding the Path Option.
(this as any).__path = options.url;
// extract the Registered Methods of the Class.
const registedMethods = Base.prototype[_registedMethods_] as Map<string, IExportMethodParameters>;
const registedParams = Base.prototype[_registedParams_] as Map<string, IExportPropertyParameters>;
// Online if they are present, iterate over them
if (registedMethods) {
registedMethods.forEach((options, methodName) => {
// Provide the code that should be exectuted for every
// Registered Function
unicorn.test.push([methodName, options]);
console.log(unicorn.test)
});
}
// Online if they are present, iterate over them
if (registedParams) {
registedParams.forEach((options, parameterName) => {
// Provide the code that should be exectuted for every
// Registered Function
unicorn.test.push([parameterName, options]);
console.log(unicorn.test)
});
}
}
};
}
}
/**
* Decorator, used to export the Method.
* @param options
*/
export function exportMethod(options: IExportMethodParameters = {}) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
target[_registedMethods_] = target[_registedMethods_] || new Map<string, IExportMethodParameters>();
// Here we just add some information that class decorator will use
target[_registedMethods_].set(propertyKey, options);
};
}
/**
* Decorator, will create a POST and GET api for the Parameter.
* @param options
*/
export function exportProperty(options: IExportPropertyParameters = {}) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
target[_registedParams_] = target[_registedParams_] || new Map<string, IExportPropertyParameters>();
// Here we just add some information that class decorator will use
target[_registedParams_].set(propertyKey, options);
};
}

View File

@ -0,0 +1,122 @@
import { BehaviorSubject, CompletionObserver, ErrorObserver, NextObserver, Subscription } from 'rxjs';
export interface nopeObserver {
active: boolean;
}
export declare type NopePartialObserver<T> = NextObserver<T> & nopeObserver | ErrorObserver<T> & nopeObserver | CompletionObserver<T> & nopeObserver;
/**
* RsJX based Observable.
*
* Contains additional Functionalities like:
* - property with the current value
* - function to publish values. (wrapper for next)
* - enables performing a subscription with synced call or a immediate call.
*/
export class nopeObservable<T> extends BehaviorSubject<T> {
protected _currentValue: T;
/**
* Getter for the Current Value.
*/
public get currentValue(): T {
return this._currentValue;
}
/**
* Setter for the Current value.
*/
public set currentValue(value: T) {
this.next(value);
}
/**
* Creates a custom Observable.
* @param initialValue
*/
constructor(initialValue: T) {
super(initialValue);
const _this = this;
this.subscribe((data) => {
_this._currentValue = data;
});
}
/**
* Function to Publish a Value to the stream.
* @param value The Value.
*/
publish(value: T) {
this.next(value);
}
subscribe(observer?: NopePartialObserver<T>, cbMode?: 'sync' | 'immediate'): Subscription;
/** @deprecated Use an observer instead of a complete callback */
subscribe(next: null | undefined, error: null | undefined, complete: () => void, cbMode?: 'sync' | 'immediate'): Subscription;
/** @deprecated Use an observer instead of an error callback */
subscribe(next: null | undefined, error: (error: any) => void, complete?: () => void, cbMode?: 'sync' | 'immediate'): Subscription;
/** @deprecated Use an observer instead of a complete callback */
subscribe(next: (value: T) => void, error: null | undefined, complete: () => void, cbMode?: 'sync' | 'immediate'): Subscription;
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void, cbMode?: 'sync' | 'immediate'): Subscription;
// Underlying implementation
subscribe(observerOrNext?, errorOrcbMode?, complete?: () => void, cbMode?: 'sync' | 'immediate'): Subscription {
// The first argument could be an Observer or Callback (Depricated) and the callbacks for complete and error
let _cbMode = cbMode;
let _error = errorOrcbMode;
let _complete = complete;
let _observerOrNext = observerOrNext;
// If the first argument is an Observer => the second argument must be the cbMode
if (typeof observerOrNext === 'object') {
// Adapt the Callback
_cbMode = errorOrcbMode || 'sync';
// The error function must be undefined
_error = undefined;
}
// Test the cbMode
if (_cbMode === 'immediate') {
switch (typeof observerOrNext) {
case 'object':
if ((observerOrNext as NopePartialObserver<T>).next) {
const orgFunc = observerOrNext.next;
observerOrNext.next = (v: T) => setImmediate(() => {
if ((observerOrNext as NopePartialObserver<T>).active) {
orgFunc.call(observerOrNext, v);
}
});
}
if ((observerOrNext as NopePartialObserver<T>).error) {
const orgFunc = observerOrNext.next;
observerOrNext.next = (v: T) => setImmediate(() => {
if ((observerOrNext as NopePartialObserver<T>).active) {
orgFunc.call(observerOrNext, v);
}
});
} if ((observerOrNext as NopePartialObserver<T>).complete) {
const orgFunc = observerOrNext.next;
observerOrNext.next = (v: T) => setImmediate(() => {
if ((observerOrNext as NopePartialObserver<T>).active) {
orgFunc.call(observerOrNext, v);
}
});
}
break;
case 'function':
_observerOrNext = typeof observerOrNext === 'function' ? (_value: T) => setImmediate(observerOrNext, _value) : observerOrNext;
break;
default:
break;
}
_error = typeof errorOrcbMode === 'function' ? (_errorValue: any) => setImmediate(errorOrcbMode, _errorValue) : undefined;
_complete = typeof complete === 'function' ? () => setImmediate(complete) : undefined;
}
return super.subscribe(_observerOrNext, _error, _complete);
}
}

View File

8
package-lock.json generated
View File

@ -5781,6 +5781,14 @@
"aproba": "^1.1.1" "aproba": "^1.1.1"
} }
}, },
"rxjs": {
"version": "6.6.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz",
"integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==",
"requires": {
"tslib": "^1.9.0"
}
},
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",

View File

@ -36,6 +36,7 @@
"react": "^16.13.1", "react": "^16.13.1",
"react-bootstrap": "^1.3.0", "react-bootstrap": "^1.3.0",
"react-dom": "^16.13.1", "react-dom": "^16.13.1",
"rxjs": "^6.6.2",
"ts-morph": "^7.3.0" "ts-morph": "^7.3.0"
}, },
"devDependencies": { "devDependencies": {

28
test/testDecorators.ts Normal file
View File

@ -0,0 +1,28 @@
import { eportApi, exportMethod, exportProperty } from "../lib/decorators";
@eportApi({
url: 'icemaker'
})
export class Icemaker {
toppings = [];
sugar = 0;
@exportMethod()
addTopping(topping) {
this.toppings.push(topping);
}
@exportMethod()
addSugar() {
this.sugar++;
}
@exportProperty()
name: string;
}
const instance = new Icemaker();
instance.addTopping('caramel')
console.log(instance)

View File

@ -0,0 +1,21 @@
import { filter } from 'rxjs/operators';
import { nopeObservable } from "../lib/observables/nopeObservable";
const observable = new nopeObservable(0);
const subscriptionSmaller = observable.pipe(
filter((v, idx) => v < 10)
).subscribe((v) => {
console.log('smaller 10:', v)
});
const subscriptionGreater = observable.pipe(
filter((v, idx) => v > 10)
).subscribe((v) => {
console.log('greater 10: ', v)
});
let i = 1;
while (i < 20) {
observable.currentValue = i++;
console.log('current', observable.currentValue);
}

View File

@ -25,7 +25,8 @@
"**/*.ts", "**/*.ts",
"helpers", "helpers",
"api", "api",
"src" "src",
"test"
], ],
"exclude": [ "exclude": [
"node_modules", "node_modules",