Skip to content

Commit

Permalink
allow deep inheritence
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcisbee committed Aug 7, 2024
1 parent 8a0615d commit a40780f
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 40 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 2.5.0

### Feature
* Allows deep inheritence.

## 2.4.4

### Other
Expand Down
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://jsr.io/schema/config-file.v1.json",
"name": "@exome/exome",
"version": "2.4.4",
"version": "2.5.0",
"publish": {
"include": ["LICENSE", "README.md", "deno.json", "package.json", "src", "logo"],
"exclude": ["src/**/*.test.ts"]
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "exome",
"version": "2.4.4",
"version": "2.5.0",
"description": "State manager for deeply nested states",
"main": "./dist/exome.js",
"module": "./dist/exome.mjs",
Expand Down
8 changes: 8 additions & 0 deletions src/constructor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ test('extended exome instance has "Person" in id', () => {
assert.match(instance[exomeId], /^Person-[A-Z0-9]+$/);
});

test('extended another class has same id', () => {
class PersonParent extends Exome {}
class Person extends PersonParent {}
const instance = new Person();

assert.match(instance[exomeId], /^Person-[A-Z0-9]+$/);
});

test("throws error for async action", async () => {
class TestStore extends Exome {
public async run() {
Expand Down
79 changes: 78 additions & 1 deletion src/utils/wrapper.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { suite } from "uvu";
import assert from "uvu/assert";

import { wrapper } from "./wrapper.ts";
import { wrapper, getAllPropertyNames } from "./wrapper.ts";

{
const test = suite("wrapper");
Expand Down Expand Up @@ -83,3 +83,80 @@ import { wrapper } from "./wrapper.ts";

test.run();
}

{
const test = suite("getAllPropertyNames");

test("exports `getAllPropertyNames`", () => {
assert.ok(getAllPropertyNames);
});

test("that `getAllPropertyNames` is function", () => {
assert.instance(getAllPropertyNames, Function);
});

test("returns all actions from TestStore", () => {
class TestStore {
constructor() {
return wrapper(this as any);
}
public test1() {}
public test2 = () => {};
public test3 = 1;
public get test4() {
return 1;
}
public set test5(v: any) {}
}
const testStore = new TestStore();

const properties = getAllPropertyNames(testStore);

assert.equal(properties, ["test1", "test5"]);
});

test("returns all actions from TestStoreParent", () => {
class TestStoreParent {
constructor() {
return wrapper(this as any);
}
public test1() {}
public test2 = () => {};
public test3 = 1;
public get test4() {
return 1;
}
public set test5(v: any) {}
}
class TestStore extends TestStoreParent {}
const testStore = new TestStore();

const properties = getAllPropertyNames(testStore);

assert.equal(properties, ["test1", "test5"]);
});

test("returns all actions from TestStoreParent2", () => {
class TestStoreParent2 {
constructor() {
return wrapper(this as any);
}
public test1() {}
public test2 = () => {};
public test3 = 1;
public get test4() {
return 1;
}
public set test5(v: any) {}
}
class TestStoreParent extends TestStoreParent2 {}
class TestStore extends TestStoreParent {}
const testStore = new TestStore();

const properties = getAllPropertyNames(testStore);

assert.equal(properties, ["test1", "test5"]);
});

test.run();
}
76 changes: 41 additions & 35 deletions src/utils/wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,49 @@ import { CONSTRUCTOR, FUNCTION } from "../constants.ts";
import { Exome } from "../constructor.ts";
import { runMiddleware } from "../middleware.ts";

export function getAllPropertyNames(obj: any) {
const props = [];

while ((obj = Object.getPrototypeOf(obj)) && obj !== Object.prototype) {
props.push(
...Object.getOwnPropertyNames(obj).filter(
(key) =>
key !== CONSTRUCTOR &&
obj.hasOwnProperty(key) &&
typeof Object.getOwnPropertyDescriptor(obj, key)?.get !== FUNCTION,
),
);
}

return props;
}

export const wrapper = <T extends Exome>(parent: T): T => {
const proto: Exome = Object.getPrototypeOf(parent) || {};

for (const key of Object.getOwnPropertyNames(proto)) {
const isGetter =
typeof Object.getOwnPropertyDescriptor(proto, key)?.get === FUNCTION;

if (!isGetter) {
const isMethod = proto.hasOwnProperty(key);
const value = (parent as any)[key];

if (
isMethod &&
parent instanceof Exome &&
key !== CONSTRUCTOR &&
typeof value === FUNCTION
) {
(parent as any)[key] = (...args: any) => {
const middleware = runMiddleware(parent, key, args);
try {
const output = value.apply(parent, args);

if (output instanceof Promise) {
return new Promise<any>((resolve, reject) => {
output
.then((result) => (middleware(), resolve(result)))
.catch((error) => (reject(error), middleware(error)));
});
}

return middleware(), output;
} catch (error) {
middleware(error as Error);
throw error;
const properties = getAllPropertyNames(parent);

for (const key of properties) {
const value = (parent as any)[key];

if (typeof value === FUNCTION) {
(parent as any)[key] = (...args: any) => {
const middleware = runMiddleware(parent, key, args);
try {
const output = value.apply(parent, args);

if (output instanceof Promise) {
return new Promise<any>((resolve, reject) => {
output
.then((result) => (middleware(), resolve(result)))
.catch((error) => (reject(error), middleware(error)));
});
}
};
}

return middleware(), output;
} catch (error) {
middleware(error as Error);
throw error;
}
};
}
}

Expand Down

0 comments on commit a40780f

Please sign in to comment.