diff --git a/src/system/decorators/gate.ts b/src/system/decorators/gate.ts index 331a1e9..5ce0fcb 100644 --- a/src/system/decorators/gate.ts +++ b/src/system/decorators/gate.ts @@ -1,22 +1,6 @@ 'use strict'; -import { Uri } from 'vscode'; import { is as isPromise } from '../promise'; - -const emptyStr = ''; - -function defaultResolver(...args: any[]): string { - if (args.length === 1) { - const arg0 = args[0]; - if (arg0 == null) return emptyStr; - if (typeof arg0 === 'string') return arg0; - if (typeof arg0 === 'number' || typeof arg0 === 'boolean' || arg0 instanceof Error) return String(arg0); - if (arg0 instanceof Uri) return arg0.toString(); - - return JSON.stringify(arg0); - } - - return JSON.stringify(args); -} +import { resolveProp } from './resolver'; export function gate any>(resolver?: (...args: Parameters) => string) { return (target: any, key: string, descriptor: PropertyDescriptor) => { @@ -31,9 +15,7 @@ export function gate any>(resolver?: (...args: Parame const gateKey = `$gate$${key}`; descriptor.value = function (this: any, ...args: any[]) { - const prop = - args.length === 0 ? gateKey : `${gateKey}$${(resolver ?? defaultResolver)(...(args as Parameters))}`; - + const prop = resolveProp(gateKey, resolver, ...(args as Parameters)); if (!Object.prototype.hasOwnProperty.call(this, prop)) { Object.defineProperty(this, prop, { configurable: false, diff --git a/src/system/decorators/memoize.ts b/src/system/decorators/memoize.ts index 93faea6..6c6ba48 100644 --- a/src/system/decorators/memoize.ts +++ b/src/system/decorators/memoize.ts @@ -1,21 +1,5 @@ 'use strict'; - -const emptyStr = ''; - -function defaultResolver(...args: any[]): string { - if (args.length === 1) { - const arg0 = args[0]; - if (arg0 == null) return emptyStr; - if (typeof arg0 === 'string') return arg0; - if (typeof arg0 === 'number' || typeof arg0 === 'boolean') { - return String(arg0); - } - - return JSON.stringify(arg0); - } - - return JSON.stringify(args); -} +import { resolveProp } from './resolver'; export function memoize any>(resolver?: (...args: Parameters) => string) { return (target: any, key: string, descriptor: PropertyDescriptor & Record) => { @@ -38,11 +22,7 @@ export function memoize any>(resolver?: (...args: Par let result; descriptor[fnKey] = function (...args: any[]) { - const prop = - fnKey === 'get' || args.length === 0 - ? memoizeKey - : `${memoizeKey}$${(resolver ?? defaultResolver)(...(args as Parameters))}`; - + const prop = resolveProp(memoizeKey, resolver, ...(args as Parameters)); if (Object.prototype.hasOwnProperty.call(this, prop)) { result = this[prop]; diff --git a/src/system/decorators/resolver.ts b/src/system/decorators/resolver.ts new file mode 100644 index 0000000..8390fbd --- /dev/null +++ b/src/system/decorators/resolver.ts @@ -0,0 +1,63 @@ +'use strict'; +import { Uri } from 'vscode'; + +function replacer(key: string, value: any): any { + if (key === '') return value; + + if (value == null) return value; + if (value instanceof Error) return String(value); + if (value instanceof Uri) { + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions + if ('sha' in (value as any) && (value as any).sha) { + return `${(value as any).sha}:${value.toString()}`; + } + return value.toString(); + } + + return value; +} + +export function defaultResolver(...args: any[]): string { + if (args.length === 0) return ''; + if (args.length !== 1) { + return JSON.stringify(args, replacer); + } + + const arg0 = args[0]; + if (arg0 == null) return ''; + if (typeof arg0 === 'string') return arg0; + if (typeof arg0 === 'number' || typeof arg0 === 'boolean' || arg0 instanceof Error) return String(arg0); + if (arg0 instanceof Uri) { + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions + if ('sha' in (arg0 as any) && (arg0 as any).sha) { + return `${(arg0 as any).sha}:${arg0.toString()}`; + } + return arg0.toString(); + } + + return JSON.stringify(arg0, replacer); +} + +export type Resolver any> = (...args: Parameters) => string; + +export function resolveProp any>( + key: string, + resolver: Resolver | undefined, + ...args: Parameters +) { + if (args.length === 0) return key; + + let resolved; + if (resolver != null) { + try { + resolved = resolver(...args); + } catch { + debugger; + resolved = defaultResolver(...(args as any)); + } + } else { + resolved = defaultResolver(...(args as any)); + } + + return `${key}$${resolved}`; +} diff --git a/src/system/decorators/serialize.ts b/src/system/decorators/serialize.ts index 99262f4..19cb0f5 100644 --- a/src/system/decorators/serialize.ts +++ b/src/system/decorators/serialize.ts @@ -1,21 +1,5 @@ 'use strict'; -import { Uri } from 'vscode'; - -const emptyStr = ''; - -function defaultResolver(...args: any[]): string { - if (args.length === 1) { - const arg0 = args[0]; - if (arg0 === undefined) return emptyStr; - if (typeof arg0 === 'string') return arg0; - if (typeof arg0 === 'number' || typeof arg0 === 'boolean' || arg0 instanceof Error) return String(arg0); - if (arg0 instanceof Uri) return arg0.toString(); - - return JSON.stringify(arg0); - } - - return JSON.stringify(args); -} +import { resolveProp } from './resolver'; export function serialize any>( resolver?: (...args: Parameters) => string, @@ -32,11 +16,7 @@ export function serialize any>( const serializeKey = `$serialize$${key}`; descriptor.value = function (this: any, ...args: any[]) { - const prop = - args.length === 0 - ? serializeKey - : `${serializeKey}$${(resolver ?? defaultResolver)(...(args as Parameters))}`; - + const prop = resolveProp(serializeKey, resolver, ...(args as Parameters)); if (!Object.prototype.hasOwnProperty.call(this, prop)) { Object.defineProperty(this, prop, { configurable: false,