107 lines
3.7 KiB
TypeScript
107 lines
3.7 KiB
TypeScript
import { constructClaimKey } from '@coinweb/contract-kit';
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
type ClaimKeyFirstPartConstructor = (...args: any[]) => unknown[];
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
type ClaimKeySecondPartConstructor = (...args: any[]) => unknown[] | null;
|
|
|
|
type ClaimKeyConstructors = {
|
|
firstPart?: ClaimKeyFirstPartConstructor;
|
|
secondPart: ClaimKeySecondPartConstructor;
|
|
};
|
|
|
|
type ClaimKey<TFirstPart extends unknown[], TSecondPart extends unknown[] | null> = {
|
|
first_part: TFirstPart;
|
|
second_part: TSecondPart;
|
|
};
|
|
|
|
export type ClaimKeyDefinitions = {
|
|
[Key: string]: ClaimKeyConstructors | ClaimKeyDefinitions;
|
|
};
|
|
|
|
type KeyConstructor<
|
|
TCreateSecondPart extends (...args: unknown[]) => unknown[] | null,
|
|
TCreateFirstPart extends ((...args: unknown[]) => unknown[]) | undefined = undefined,
|
|
> = {
|
|
firstPart: TCreateFirstPart extends ClaimKeyFirstPartConstructor
|
|
? (...args: Parameters<TCreateFirstPart>) => [string, ...ReturnType<TCreateFirstPart>]
|
|
: () => [string];
|
|
secondPart: TCreateSecondPart;
|
|
} & (TCreateFirstPart extends ClaimKeySecondPartConstructor
|
|
? (
|
|
...args: [...Parameters<TCreateFirstPart>, ...Parameters<TCreateSecondPart>]
|
|
) => ClaimKey<[string, ...ReturnType<TCreateFirstPart>], ReturnType<TCreateSecondPart>>
|
|
: (...args: Parameters<TCreateSecondPart>) => ClaimKey<[string], ReturnType<TCreateSecondPart>>);
|
|
|
|
type ConstructKeys<T extends ClaimKeyDefinitions> = {
|
|
[Key in keyof T]: T[Key] extends ClaimKeyDefinitions
|
|
? ConstructKeys<T[Key]>
|
|
: T[Key] extends ClaimKeyConstructors
|
|
? KeyConstructor<T[Key]['secondPart'], T[Key]['firstPart']>
|
|
: never;
|
|
};
|
|
|
|
const domainPropSymbol = Symbol('domain');
|
|
|
|
export const constructClaimKeys = <T extends ClaimKeyDefinitions>(domain: string, keys: T): ConstructKeys<T> =>
|
|
new Proxy(keys as ClaimKeyDefinitions & { [domainPropSymbol]?: string }, {
|
|
get: (target, prop) => {
|
|
if (typeof prop !== 'string') {
|
|
throw new Error('Property is not a string');
|
|
}
|
|
|
|
const value = target[prop];
|
|
const currentDomain = target[domainPropSymbol] ? `${target[domainPropSymbol]}_${prop}` : domain;
|
|
|
|
if ('secondPart' in value) {
|
|
const secondPart = value.secondPart;
|
|
|
|
const firstPartDefinedConstructor = value.firstPart;
|
|
|
|
if (typeof firstPartDefinedConstructor === 'function') {
|
|
const firstPart = (...args: Parameters<typeof firstPartDefinedConstructor>) => [
|
|
currentDomain,
|
|
...firstPartDefinedConstructor(...args),
|
|
];
|
|
|
|
return {
|
|
firstPart,
|
|
secondPart,
|
|
};
|
|
}
|
|
|
|
return {
|
|
firstPart: () => [currentDomain],
|
|
secondPart,
|
|
};
|
|
}
|
|
|
|
(value as ClaimKeyDefinitions & { [domainPropSymbol]: string })[domainPropSymbol] = currentDomain;
|
|
|
|
return value;
|
|
},
|
|
apply(target, prop, argArray) {
|
|
const value = target[prop];
|
|
const currentDomain = target[domainPropSymbol] ? `${target[domainPropSymbol]}_${prop}` : domain;
|
|
|
|
const secondPartConstructor = value.secondPart;
|
|
|
|
if (typeof secondPartConstructor !== 'function') {
|
|
throw new Error('Property is not callable');
|
|
}
|
|
|
|
const secondPartArgs = argArray.slice(argArray.length - secondPartConstructor.length);
|
|
const secondPart = secondPartConstructor(...secondPartArgs);
|
|
|
|
const firstPartDefinedConstructor = value.firstPart;
|
|
|
|
const firstPart: unknown[] = [currentDomain];
|
|
|
|
if (typeof firstPartDefinedConstructor === 'function') {
|
|
firstPart.push(...firstPartDefinedConstructor(...argArray));
|
|
}
|
|
|
|
return constructClaimKey(firstPart, secondPart);
|
|
},
|
|
}) as ConstructKeys<T>;
|