Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace new decorators with the old ones #180

Merged
merged 1 commit into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,21 +140,38 @@ const enum Inline {
Repository = 1,
}

// function command(repository?: 1) {
// return (
// fn: CommandMethod,
// context: ClassMethodDecoratorContext<CommandCenter, CommandMethod> & {
// name: CommandKey;
// }
// ) => {
// if (repository) {
// fn = makeCommandWithRepository(fn);
// }
// register.push({
// id: `fossil.${context.name as CommandKey}`,
// method: fn,
// });
// return fn;
// };
// }

function command(repository?: 1) {
return (
fn: CommandMethod,
context: ClassMethodDecoratorContext<CommandCenter, CommandMethod> & {
name: CommandKey;
}
_target: any,
key: CommandKey,
descriptor: TypedPropertyDescriptor<CommandMethod>
) => {
let fn = descriptor.value!;
if (repository) {
fn = makeCommandWithRepository(fn);
}
register.push({
id: `fossil.${context.name as CommandKey}`,
id: `fossil.${key}`,
method: fn,
});
return fn;
};
}

Expand Down
153 changes: 115 additions & 38 deletions src/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,89 +6,166 @@

import { done } from './util';

export function memoize<Return extends {}>(
target: (this: Record<string, Return>) => Return,
context: ClassGetterDecoratorContext
// export function memoize<Return extends {}>(
// target: (this: Record<string, Return>) => Return,
// context: ClassGetterDecoratorContext
// ) {
// const memoizeKey = `$memoize$${context.name as string}`;
// return function (this: Record<string, Return>): Return {
// if (!this[memoizeKey]) {
// this[memoizeKey] = target.apply(this);
// }
// return this[memoizeKey];
// };
// }
export function memoize<Return>(
target: any,
key: string,
descriptor: PropertyDescriptor
) {
const memoizeKey = `$memoize$${context.name as string}`;
return function (this: Record<string, Return>): Return {
const memoizeKey = `$memoize$${key}`;
const fn = descriptor.get!;
descriptor.get = function (this: Record<string, Return>): Return {
if (!this[memoizeKey]) {
this[memoizeKey] = target.apply(this);
this[memoizeKey] = fn.apply(this);
}
return this[memoizeKey];
};
}

/**
* Decorator to not allow multiple async calls
*/
export function throttle<Args extends any[], T>(
target: (
this: Record<string, Promise<T> | undefined>,
...args: Args
) => Promise<T>,
context: ClassMethodDecoratorContext
) {
const currentKey = `$thr$c$${String(context.name)}`; // $throttle$current$
const nextKey = `$thr$n$${String(context.name)}`; // $throttle$next$
// export function throttle<Args extends any[], T>(
// target: (
// this: Record<string, Promise<T> | undefined>,
// ...args: Args
// ) => Promise<T>,
// context: ClassMethodDecoratorContext
// ) {
// const currentKey = `$thr$c$${String(context.name)}`; // $throttle$current$
// const nextKey = `$thr$n$${String(context.name)}`; // $throttle$next$

// const trigger = function (
// this: Record<string, Promise<T> | undefined>,
// ...args: Args
// ): Promise<T> {
// if (this[nextKey]) {
// return this[nextKey]!;
// }

// if (this[currentKey]) {
// this[nextKey] = done(this[currentKey]!).then(() => {
// this[nextKey] = undefined;
// return trigger.apply(this, args);
// });

// return this[nextKey]!;
// }

// this[currentKey] = target.apply(this, args);

// const clear = () => (this[currentKey] = undefined);
// done(this[currentKey]!).then(clear, clear);

const trigger = function (
this: Record<string, Promise<T> | undefined>,
...args: Args
): Promise<T> {
// return this[currentKey]!;
// };

// return trigger;
// }
export function throttle(
target: any,
key: string,
descriptor: PropertyDescriptor
): void {
const currentKey = `$thr$c$${key}`; // $throttle$current$
const nextKey = `$thr$n$${key}`; // $throttle$next$
const fn = descriptor.value!;

descriptor.value = function (
this: Record<string, Promise<any> | undefined>,
...args: any
): Promise<any> {
if (this[nextKey]) {
return this[nextKey]!;
}

if (this[currentKey]) {
this[nextKey] = done(this[currentKey]!).then(() => {
this[nextKey] = undefined;
return trigger.apply(this, args);
return fn.apply(this, args);
});

return this[nextKey]!;
}

this[currentKey] = target.apply(this, args);
this[currentKey] = fn.apply(this, args);

const clear = () => (this[currentKey] = undefined);
done(this[currentKey]!).then(clear, clear);

return this[currentKey]!;
};

return trigger;
}

// Make sure asynchronous functions are called one after another.
type ThisPromise = Record<string, Promise<any>>;
// type ThisPromise = Record<string, Promise<any>>;

export function sequentialize<Args extends any[]>(
target: (this: ThisPromise, ...args: Args) => Promise<any>,
context: ClassMethodDecoratorContext
// export function sequentialize<Args extends any[]>(
// target: (this: ThisPromise, ...args: Args) => Promise<any>,
// context: ClassMethodDecoratorContext
// ) {
// const currentKey = `$s11e$${context.name as string}`; // sequentialize

// return function (this: ThisPromise, ...args: Args): Promise<any> {
// const currentPromise =
// (this[currentKey] as Promise<any>) || Promise.resolve(null);
// const run = async () => await target.apply(this, args);
// this[currentKey] = currentPromise.then(run, run);
// return this[currentKey];
// };
// }

export function sequentialize(
target: any,
key: string,
descriptor: PropertyDescriptor
) {
const currentKey = `$s11e$${context.name as string}`; // sequentialize
const currentKey = `$s11e$${key}`; // sequentialize
const fn = descriptor.value!;

return function (this: ThisPromise, ...args: Args): Promise<any> {
descriptor.value = function (this: any, ...args: any): Promise<any> {
const currentPromise =
(this[currentKey] as Promise<any>) || Promise.resolve(null);
const run = async () => await target.apply(this, args);
const run = async () => await fn.apply(this, args);
this[currentKey] = currentPromise.then(run, run);
return this[currentKey];
};
}

type ThisTimer = Record<string, ReturnType<typeof setTimeout>>;
// type ThisTimer = Record<string, ReturnType<typeof setTimeout>>;

// export function debounce(delay: number) {
// return function <Args extends any[]>(
// target: (this: ThisTimer, ...args: Args) => void,
// context: ClassMemberDecoratorContext
// ) {
// const timerKey = `$d6e$${String(context.name)}`; // debounce

// return function (this: ThisTimer, ...args: Args): void {
// clearTimeout(this[timerKey]);
// this[timerKey] = setTimeout(() => target.apply(this, args), delay);
// };
// };
// }
export function debounce(delay: number) {
return function <Args extends any[]>(
target: (this: ThisTimer, ...args: Args) => void,
context: ClassMemberDecoratorContext
) {
const timerKey = `$d6e$${String(context.name)}`; // debounce
return function (target: any, key: string, descriptor: PropertyDescriptor) {
const timerKey = `$d6e$${key}`; // debounce
const fn = descriptor.value!;

return function (this: ThisTimer, ...args: Args): void {
descriptor.value = function (this: any, ...args: any): void {
clearTimeout(this[timerKey]);
this[timerKey] = setTimeout(() => target.apply(this, args), delay);
this[timerKey] = setTimeout(() => fn.apply(this, args), delay);
};
};
}
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"removeComments": true,
"sourceMap": true,
"strictNullChecks": true,
"experimentalDecorators": true,
},
"include": [
"src/**/*",
Expand Down