Skip to content

Commit

Permalink
Merge pull request #2 from pilsy/fix/decorators-use-reflect
Browse files Browse the repository at this point in the history
fix(decorators): Use reflect metadata
  • Loading branch information
pilsy authored Sep 16, 2024
2 parents 4ca6221 + c8fac25 commit a023bc1
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 71 deletions.
11 changes: 9 additions & 2 deletions package-lock.json

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

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "chrono-forge",
"version": "0.6.10",
"version": "0.7.0",
"description": "A comprehensive framework for building resilient Temporal workflows, advanced state management, and real-time streaming activities in TypeScript. Designed for a seamless developer experience with powerful abstractions, dynamic orchestration, and full control over distributed systems.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down Expand Up @@ -88,6 +88,7 @@
"lodash.isequal": "^4.5.0",
"lodash.isobject": "^3.0.2",
"normalizr": "^3.6.2",
"reflect-metadata": "^0.2.2",
"ws": "^8.18.0"
},
"devDependencies": {
Expand Down
10 changes: 6 additions & 4 deletions src/decorators/Get.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'reflect-metadata'; // Ensure reflect-metadata is imported
import { GETTER_METADATA_KEY } from '../workflows/Workflow';

export const Get = (name?: string) => {
return (target: any, propertyKey: string) => {
if (!target.constructor._getters) {
target.constructor._getters = {};
}
target.constructor._getters[name || propertyKey] = propertyKey;
const getters = Reflect.getMetadata(GETTER_METADATA_KEY, target) || {};
getters[name || propertyKey] = propertyKey;
Reflect.defineMetadata(GETTER_METADATA_KEY, getters, target);
};
};
29 changes: 17 additions & 12 deletions src/decorators/Property.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
import 'reflect-metadata';
import { PROPERTY_METADATA_KEY, GETTER_METADATA_KEY, SETTER_METADATA_KEY } from '../workflows/Workflow';

export const Property = (options: { get?: boolean | string; set?: boolean | string } = {}) => {
return (target: any, propertyKey: string) => {
if (!target.constructor._properties) {
target.constructor._properties = [];
}
const properties = Reflect.getMetadata(PROPERTY_METADATA_KEY, target) || [];

const queryName = `query${capitalize(typeof options.get === 'string' ? options.get : propertyKey)}`;
const signalName = `signal${capitalize(typeof options.set === 'string' ? options.set : propertyKey)}`;
// const queryName = `query${capitalize(typeof options.get === 'string' ? options.get : propertyKey)}`;
// const signalName = `signal${capitalize(typeof options.set === 'string' ? options.set : propertyKey)}`;

target.constructor._properties.push({
properties.push({
propertyKey,
get: options.get || options.get === undefined,
set: options.set || options.set === undefined,
queryName,
signalName
queryName: propertyKey,
signalName: propertyKey
});

Reflect.defineMetadata(PROPERTY_METADATA_KEY, properties, target);

if (options.get) {
const getterName = typeof options.get === 'string' ? options.get : propertyKey;
target.constructor._getters = target.constructor._getters || {};
target.constructor._getters[getterName] = propertyKey;
const getters = Reflect.getMetadata(GETTER_METADATA_KEY, target) || {};
getters[getterName] = propertyKey;
Reflect.defineMetadata(GETTER_METADATA_KEY, getters, target);
}

if (options.set) {
const setterName = typeof options.set === 'string' ? options.set : propertyKey;
target.constructor._setters = target.constructor._setters || {};
target.constructor._setters[setterName] = propertyKey;
const setters = Reflect.getMetadata(SETTER_METADATA_KEY, target) || {};
setters[setterName] = propertyKey;
Reflect.defineMetadata(SETTER_METADATA_KEY, setters, target);
}
};
};
Expand Down
10 changes: 6 additions & 4 deletions src/decorators/Query.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'reflect-metadata';
import { QUERY_METADATA_KEY } from '../workflows/Workflow';

export const Query = (name?: string) => {
return (target: any, propertyKey: string) => {
if (!target.constructor._queries) {
target.constructor._queries = [];
}
target.constructor._queries.push([name || propertyKey, propertyKey]);
const queries = Reflect.getMetadata(QUERY_METADATA_KEY, target) || [];
queries.push([name || propertyKey, propertyKey]);
Reflect.defineMetadata(QUERY_METADATA_KEY, queries, target);
};
};
10 changes: 6 additions & 4 deletions src/decorators/Set.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'reflect-metadata'; // Ensure reflect-metadata is imported
import { SETTER_METADATA_KEY } from '../workflows/Workflow';

export const Set = (name?: string) => {
return (target: any, propertyKey: string) => {
if (!target.constructor._setters) {
target.constructor._setters = {};
}
target.constructor._setters[name || propertyKey] = propertyKey;
const setters = Reflect.getMetadata(SETTER_METADATA_KEY, target) || {};
setters[name || propertyKey] = propertyKey;
Reflect.defineMetadata(SETTER_METADATA_KEY, setters, target);
};
};
10 changes: 6 additions & 4 deletions src/decorators/Signal.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'reflect-metadata';
import { SIGNAL_METADATA_KEY } from '../workflows/Workflow';

export const Signal = (name?: string) => {
return (target: any, propertyKey: string) => {
if (!target.constructor._signals) {
target.constructor._signals = [];
}
target.constructor._signals.push([name || propertyKey, propertyKey]);
const signals = Reflect.getMetadata(SIGNAL_METADATA_KEY, target) || [];
signals.push([name || propertyKey, propertyKey]);
Reflect.defineMetadata(SIGNAL_METADATA_KEY, signals, target);
};
};
88 changes: 48 additions & 40 deletions src/workflows/Workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import EventEmitter from 'eventemitter3';
import { get } from 'dottie';
import { registry } from '../WorkflowRegistry';
import { Property, Signal, Query, On } from '../decorators';
import 'reflect-metadata';

/**
* `Workflow` Class
Expand Down Expand Up @@ -52,6 +53,12 @@ export interface ChronoFlowOptions {
[key: string]: any;
}

export const PROPERTY_METADATA_KEY = Symbol('property');
export const QUERY_METADATA_KEY = Symbol('query');
export const SIGNAL_METADATA_KEY = Symbol('signal');
export const GETTER_METADATA_KEY = Symbol('getter');
export const SETTER_METADATA_KEY = Symbol('setter');

/**
* `ChronoFlow` Decorator
*
Expand Down Expand Up @@ -490,35 +497,22 @@ export abstract class Workflow<P = unknown, O = unknown> extends EventEmitter {
if (!!proto._propertiesBound) {
return;
}
(proto.constructor._properties || []).forEach(
({
propertyKey,
get: g,
set: s,
queryName,
signalName
}: {
propertyKey: string;
get: boolean | string;
set: boolean | string;
queryName: string;
signalName: string;
}) => {
if (g) {
const getter = get(proto, `constructor._getters.${propertyKey}`, () => (this as any)[propertyKey]);
// @ts-ignore
this.queryHandlers[propertyKey] = getter.bind(this);
}
const properties = this.collectMetadata(PROPERTY_METADATA_KEY);
properties.forEach(({ propertyKey, get: g, set: s, queryName, signalName }) => {
if (g) {
const getter = () => (this as any)[propertyKey];
this.queryHandlers[queryName] = getter.bind(this);
// @ts-ignore
workflow.setHandler(workflow.defineQuery(queryName), getter);
}

if (s) {
const setter = get(proto, `constructor._setters.${propertyKey}`, (value: any) => {
(this as any)[propertyKey] = value;
});
// @ts-ignore
this.signalHandlers[propertyKey] = setter.bind(this);
}
if (s) {
const setter = (value: any) => ((this as any)[propertyKey] = value);
this.signalHandlers[signalName] = setter.bind(this);
// @ts-ignore
workflow.setHandler(workflow.defineSignal(signalName), setter);
}
);
});
this._propertiesBound = true;
}

Expand All @@ -528,12 +522,14 @@ export abstract class Workflow<P = unknown, O = unknown> extends EventEmitter {
if (!!proto._queriesBound) {
return;
}
(Object.getPrototypeOf(this).constructor._queries || []).forEach(([queryName, queryMethod]: [string, string]) => {
this.queryHandlers[queryName] =
queryMethod && typeof (this as any)[queryMethod] === 'function' ? (this as any)[queryMethod]?.bind(this) : this.queryHandlers[queryName];
});
for (const [name, method] of Object.entries(this.queryHandlers)) {
workflow.setHandler(workflow.defineQuery(name), method);
const queries = this.collectMetadata(QUERY_METADATA_KEY);
for (const [queryName, queryMethod] of queries) {
if (typeof (this as any)[queryMethod] === 'function') {
const handler = (this as any)[queryMethod].bind(this);
this.queryHandlers[queryName] = handler;
// @ts-ignore
workflow.setHandler(workflow.defineQuery(queryName), handler);
}
}
this._queriesBound = true;
}
Expand All @@ -544,14 +540,26 @@ export abstract class Workflow<P = unknown, O = unknown> extends EventEmitter {
if (!!proto._signalsBound) {
return;
}
(Object.getPrototypeOf(this).constructor._signals || []).forEach(([signalName, signalMethod]: [string, string]) => {
this.signalHandlers[signalName] = this.signalHandlers[signalName] || (this as any)[signalMethod]?.bind(this);
workflow.setHandler(workflow.defineSignal(signalName), async (...args: any[]) => {
await this.emitAsync(signalName, args);
const signals = this.collectMetadata(SIGNAL_METADATA_KEY);
for (const [signalName, signalMethod] of signals) {
if (typeof (this as any)[signalMethod] === 'function') {
const handler = (this as any)[signalMethod].bind(this);
this.signalHandlers[signalName] = handler;
// @ts-ignore
return await this.signalHandlers[signalName](...(args as []));
});
});
workflow.setHandler(workflow.defineSignal(signalName), handler);
}
}
this._signalsBound = true;
}

private collectMetadata(metadataKey: Symbol): any[] {
const collectedMetadata: any[] = [];
let currentProto = Object.getPrototypeOf(this);
while (currentProto && currentProto !== Workflow.prototype) {
const metadata = Reflect.getMetadata(metadataKey, currentProto) || [];
collectedMetadata.push(...metadata);
currentProto = Object.getPrototypeOf(currentProto);
}
return collectedMetadata;
}
}

0 comments on commit a023bc1

Please sign in to comment.