feat: add public method utilities and corresponding tests

This commit is contained in:
tone
2025-11-15 18:07:21 +08:00
parent 36e0c17ad7
commit ab289186f1
4 changed files with 70 additions and 3 deletions

View File

@@ -1,4 +1,4 @@
import { getRandomAvailablePort, isObject, isString, makeId } from "@/utils/utils"
import { getRandomAvailablePort, isObject, isPublicMethod, isString, makeId, markAsPublicMethod } from "@/utils/utils"
test('makeId', () => {
const id = makeId();
@@ -26,4 +26,29 @@ test('getRandomAvailablePort', async () => {
const port = await getRandomAvailablePort();
expect(port).toBeGreaterThanOrEqual(1);
expect(port).toBeLessThanOrEqual(65535);
})
test('markAsPublick', () => {
const shallowObj = {
fn1() { },
l1: {
fn1() { },
}
};
const deepObj = {
fn1() { },
l1: {
fn1() { },
}
};
markAsPublicMethod(shallowObj);
markAsPublicMethod(deepObj, { deep: true });
expect(isPublicMethod(shallowObj.fn1)).toBeTruthy();
expect(isPublicMethod(shallowObj.l1.fn1)).toBeUndefined();
expect(isPublicMethod(deepObj.fn1)).toBeTruthy();
expect(isPublicMethod(deepObj.l1.fn1)).toBeTruthy();
})

View File

@@ -16,6 +16,8 @@ export { injectSocketClient } from "./core/SocketClient";
export { injectSocketServer } from "./core/SocketServer";
import { injectSocketIOImplements } from "./implements/socket.io";
export { publicMethod, isPublicMethod, markAsPublicMethod } from './utils/utils';
injectSocketIOImplements();
export {

View File

@@ -4,8 +4,12 @@ export const makeId = () => md5(`${Date.now()}${Math.random()}`);
export const isObject = (v: unknown): v is Record<string, any> => typeof v === 'object' && v !== null;
export const isArray = (v: unknown): v is Array<unknown> => Array.isArray(v);
export const isString = (v: unknown): v is string => typeof v === 'string';
export const isFunction = (v: unknown): v is Function => typeof v === 'function';
export type ObjectType = Record<string, any>;
export type ToDeepPromise<T> = {
@@ -41,4 +45,40 @@ export async function getRandomAvailablePort() {
server.listen(0);
})
}
const publicMethodMap = new WeakMap<Function, boolean>();
export function publicMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
publicMethodMap.set(descriptor.value, true);
};
export function isPublicMethod(target: Function) {
return publicMethodMap.get(target);
};
export function markAsPublicMethod<T extends Function | Record<any, unknown> | unknown>(obj: T, options?: {
deep?: boolean
}): T {
const accessed = new Set();
function markAs(obj: Function | Record<any, unknown> | unknown) {
if (accessed.has(obj)) {
return;
}
if (isFunction(obj)) {
publicMethodMap.set(obj, true);
} else if (isObject(obj)) {
accessed.add(obj);
Object.values(obj).forEach(subObj => {
if (isFunction(subObj)) {
publicMethodMap.set(subObj, true);
}
if (options?.deep && isObject(subObj)) {
markAs(subObj);
}
});
}
}
markAs(obj);
return obj;
}

View File

@@ -12,8 +12,8 @@
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
"experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
"emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */