import { isObject , isDefined } from '@esfx/internal-guards' ; import { createMemberDescriptor , createParameterDescriptor , createDecoratorFactory , DecoratorDescriptor , MemberDescriptor , ParameterDescriptor , isClass , isMember , isParameter , ClassDescriptor } from '@esfx/decorators-stage1-core' ; export type MetadataKey = string | symbol | number | boolean | bigint | object ; interface ObjectDescriptor { kind : "object" ; target : object ; } interface ObjectMetadata extends Map < MetadataKey , unknown > { _kind : "object" ; _parent : WeakMap < object , ObjectMetadata > ; _key : object ; } interface MembersMetadata extends Map < string | symbol , MemberMetadata > { _parent : WeakMap < object , MembersMetadata > ; _key : object ; } interface MemberMetadata extends Map < MetadataKey , unknown > { _kind : "member" ; _parent : MembersMetadata ; _key : string | symbol ; } interface MethodsMetadata extends Map < string | symbol , MethodMetadata > { _parent : WeakMap < object , MethodsMetadata > ; _key : object ; } interface MethodMetadata extends Map < number , ParameterMetadata > { _parent : MethodsMetadata ; _key : string | symbol ; } interface ParameterMetadata extends Map < MetadataKey , unknown > { _kind : "parameter" ; _parent : MethodMetadata ; _key : number ; } interface MetadataRoot { delete ( key ) : boolean ; } interface MetadataNode { readonly _parent : MetadataNode | MetadataRoot ; readonly _key : unknown ; readonly size : number ; delete ( key ) : boolean ; } type MetadataSelector = ObjectDescriptor | MemberDescriptor | ParameterDescriptor ; type MetadataSelection = ObjectMetadata | MemberMetadata | ParameterMetadata ; const hasOwn = Function . prototype . call . bind ( Object . prototype . hasOwnProperty ) as ( target : object , propertyKey : PropertyKey ) => boolean ; const weakObjectMetadata = new WeakMap < object , ObjectMetadata > ( ) ; const weakMemberMetadata = new WeakMap < object , MembersMetadata > ( ) ; const weakParameterMetadata = new WeakMap < object , MethodsMetadata > ( ) ; function createObjectDescriptor ( target ) { return { kind : "object" , target } ; } function selectMetadata < S extends MetadataSelector > ( selector , create ) ; function selectMetadata < S extends MetadataSelector > ( selector , create ) ; function selectMetadata ( selector , create ) { switch ( selector . kind ) { case "object" : return selectObjectMetadata ( selector , create ) ; case "member" : return selectMemberMetadata ( selector , create ) ; case "parameter" : return selectParameterMetadata ( selector , create ) ; } } function selectObjectMetadata ( { target } , create ) { let objectMetadata = weakObjectMetadata . get ( target ) ; if ( ! objectMetadata ) { if ( ! create ) return undefined ; weakObjectMetadata . set ( target , objectMetadata = Object . assign ( new Map ( ) , { _kind : "object" , _parent : weakObjectMetadata , _key : target } as const ) ) ; } return objectMetadata ; } function selectMemberMetadata ( { target , key } , create ) { let membersMetadata = weakMemberMetadata . get ( target ) ; if ( ! membersMetadata ) { if ( ! create ) return undefined ; weakMemberMetadata . set ( target , membersMetadata = Object . assign ( new Map ( ) , { _parent : weakMemberMetadata , _key : target } as const ) ) ; } let memberMetadata = membersMetadata . get ( key ) ; if ( ! memberMetadata ) { if ( ! create ) return undefined ; membersMetadata . set ( key , memberMetadata = Object . assign ( new Map ( ) , { _kind : "member" , _parent : membersMetadata , _key : key } as const ) ) ; } return memberMetadata ; } function selectParameterMetadata ( { target , key , index } , create ) { let methodsMetadata = weakParameterMetadata . get ( target ) ; if ( ! methodsMetadata ) { if ( ! create ) return undefined ; weakParameterMetadata . set ( target , methodsMetadata = Object . assign ( new Map ( ) , { _parent : weakParameterMetadata , _key : target } as const ) ) ; } let methodMetadata = methodsMetadata . get ( key ) ; if ( ! methodMetadata ) { if ( ! create ) return undefined ; methodsMetadata . set ( key , methodMetadata = Object . assign ( new Map ( ) , { _parent : methodsMetadata , _key : key } as const ) ) ; } let parameterMetadata = methodMetadata . get ( index ) ; if ( ! parameterMetadata ) { if ( ! create ) return undefined ; methodMetadata . set ( index , parameterMetadata = Object . assign ( new Map ( ) , { _kind : "parameter" , _parent : methodMetadata , _key : index } as const ) ) ; } return parameterMetadata ; } function hasOwnMember ( selector ) { return hasOwn ( selector . target , selector . key ) ; } function defineMetadata ( selector , metadataKey , metadataValue ) { const selection = selectMetadata ( selector , true ) ; selection . set ( metadataKey , metadataValue ) ; } function deleteMetadata ( selector , metadataKey ) { let selection = selectMetadata ( selector , false ) ; if ( selection && selection . delete ( metadataKey ) ) { let node = selection as MetadataNode ; while ( node . size === 0 ) { node . _parent . delete ( node . _key ) ; if ( ! ( "_parent" in node . _parent ) ) break ; node = node . _parent ; } return true ; } return false ; } function hasOwnMetadata ( selector , metadataKey ) { const selection = selectMetadata ( selector , false ) ; return selection ? selection . has ( metadataKey ) : false ; } function hasMetadata ( selector , metadataKey ) { return walk ( selector , selector => hasOwnMetadata ( selector , metadataKey ) , T , false , false ) ; } function getOwnMetadata ( selector , metadataKey ) { const selection = selectMetadata ( selector , false ) ; return selection ? selection . get ( metadataKey ) : undefined ; } function getMetadata ( selector , metadataKey ) { return walk ( selector , selector => hasOwnMetadata ( selector , metadataKey ) , selector => getOwnMetadata ( selector , metadataKey ) , false , undefined ) ; } function getOwnMetadataKeys ( selector ) { const selection = selectMetadata ( selector , false ) ; return selection ? [ ... selection . keys ( ) ] : [ ] ; } function getMetadataKeysReducer ( selector , keys ) { for ( const key of getOwnMetadataKeys ( selector ) ) { keys . add ( key ) ; } return keys ; } function getMetadataKeys ( selector ) { const keys = walk ( selector , T , getMetadataKeysReducer , true , new Set < MetadataKey > ( ) ) ; return [ ... keys ] ; } param target param metadataKey param metadataValue export function defineObjectMetadata ( target , metadataKey , metadataValue ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; defineMetadata ( createObjectDescriptor ( target ) , metadataKey , metadataValue ) ; } param target param metadataKey export function deleteObjectMetadata ( target , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return deleteMetadata ( createObjectDescriptor ( target ) , metadataKey ) ; } param target param metadataKey export function hasOwnObjectMetadata ( target , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return hasOwnMetadata ( createObjectDescriptor ( target ) , metadataKey ) ; } param target param metadataKey export function hasObjectMetadata ( target , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return hasMetadata ( createObjectDescriptor ( target ) , metadataKey ) ; } param target param metadataKey export function getOwnObjectMetadata ( target , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return getOwnMetadata ( createObjectDescriptor ( target ) , metadataKey ) ; } param target param metadataKey export function getObjectMetadata ( target , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return getMetadata ( createObjectDescriptor ( target ) , metadataKey ) ; } param target export function getOwnObjectMetadataKeys ( target ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; return getOwnMetadataKeys ( createObjectDescriptor ( target ) ) ; } param target export function getObjectMetadataKeys ( target ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; return getMetadataKeys ( createObjectDescriptor ( target ) ) ; } function addMetadataMembers ( target , members ) { const membersMetadata = weakMemberMetadata . get ( target ) ; const methodsMetadata = weakParameterMetadata . get ( target ) ; if ( membersMetadata ) addRange ( members , membersMetadata . keys ( ) ) ; if ( methodsMetadata ) addRange ( members , methodsMetadata . keys ( ) ) ; } param target param propertyKey param metadataKey param metadataValue export function definePropertyMetadata ( target , propertyKey , metadataKey , metadataValue ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; defineMetadata ( createMemberDescriptor ( target , propertyKey ) , metadataKey , metadataValue ) ; } param target param propertyKey param metadataKey export function deletePropertyMetadata ( target , propertyKey , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return deleteMetadata ( createMemberDescriptor ( target , propertyKey ) , metadataKey ) ; } param target param propertyKey param metadataKey export function hasOwnPropertyMetadata ( target , propertyKey , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return hasOwnMetadata ( createMemberDescriptor ( target , propertyKey ) , metadataKey ) ; } param target param propertyKey param metadataKey export function hasPropertyMetadata ( target , propertyKey , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return hasMetadata ( createMemberDescriptor ( target , propertyKey ) , metadataKey ) ; } param target param propertyKey param metadataKey export function getOwnPropertyMetadata ( target , propertyKey , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return getOwnMetadata ( createMemberDescriptor ( target , propertyKey ) , metadataKey ) ; } param target param propertyKey param metadataKey export function getPropertyMetadata ( target , propertyKey , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return getMetadata ( createMemberDescriptor ( target , propertyKey ) , metadataKey ) ; } param target param propertyKey export function getOwnPropertyMetadataKeys ( target , propertyKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; return getOwnMetadataKeys ( createMemberDescriptor ( target , propertyKey ) ) ; } param target param propertyKey export function getPropertyMetadataKeys ( target , propertyKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; return getMetadataKeys ( createMemberDescriptor ( target , propertyKey ) ) ; } param target export function getOwnMetadataProperties ( target ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; const members = new Set < string | symbol > ( ) ; addMetadataMembers ( target , members ) ; return [ ... members ] ; } param target export function getMetadataProperties ( target ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; const members = new Set < string | symbol > ( ) ; let current = target ; while ( isObject ( current ) ) { addMetadataMembers ( current , members ) ; current = Object . getPrototypeOf ( current ) ; } return [ ... members ] ; } param target param propertyKey param parameterIndex param metadataKey param metadataValue export function defineParameterMetadata ( target , propertyKey , parameterIndex , metadataKey , metadataValue ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( typeof parameterIndex !== "number" ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; defineMetadata ( createParameterDescriptor ( target , propertyKey , parameterIndex ) , metadataKey , metadataValue ) ; } param target param propertyKey param parameterIndex param metadataKey export function deleteParameterMetadata ( target , propertyKey , parameterIndex , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( typeof parameterIndex !== "number" ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return deleteMetadata ( createParameterDescriptor ( target , propertyKey , parameterIndex ) , metadataKey ) ; } param target param propertyKey param parameterIndex param metadataKey export function hasOwnParameterMetadata ( target , propertyKey , parameterIndex , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( typeof parameterIndex !== "number" ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return hasOwnMetadata ( createParameterDescriptor ( target , propertyKey , parameterIndex ) , metadataKey ) ; } param target param propertyKey param parameterIndex param metadataKey export function hasParameterMetadata ( target , propertyKey , parameterIndex , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( typeof parameterIndex !== "number" ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return hasMetadata ( createParameterDescriptor ( target , propertyKey , parameterIndex ) , metadataKey ) ; } param target param propertyKey param parameterIndex param metadataKey export function getOwnParameterMetadata ( target , propertyKey , parameterIndex , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( typeof parameterIndex !== "number" ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return getOwnMetadata ( createParameterDescriptor ( target , propertyKey , parameterIndex ) , metadataKey ) ; } param target param propertyKey param parameterIndex param metadataKey export function getParameterMetadata ( target , propertyKey , parameterIndex , metadataKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( typeof parameterIndex !== "number" ) throw new TypeError ( ) ; if ( ! isDefined ( metadataKey ) ) throw new TypeError ( ) ; return getMetadata ( createParameterDescriptor ( target , propertyKey , parameterIndex ) , metadataKey ) ; } param target param propertyKey param parameterIndex export function getOwnParameterMetadataKeys ( target , propertyKey , parameterIndex ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( typeof parameterIndex !== "number" ) throw new TypeError ( ) ; return getOwnMetadataKeys ( createParameterDescriptor ( target , propertyKey , parameterIndex ) ) ; } param target param propertyKey param parameterIndex export function getParameterMetadataKeys ( target , propertyKey , parameterIndex ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; if ( typeof parameterIndex !== "number" ) throw new TypeError ( ) ; return getMetadataKeys ( createParameterDescriptor ( target , propertyKey , parameterIndex ) ) ; } function getOwnMetadataMaxParameterIndex ( { target , key } ) { let maxParameterIndex = - 1 ; const membersMetadata = weakParameterMetadata . get ( target ) ; if ( membersMetadata ) { const parametersMetadata = membersMetadata . get ( key ) ; if ( parametersMetadata ) { for ( const parameterIndex of parametersMetadata . keys ( ) ) { if ( parameterIndex > maxParameterIndex ) maxParameterIndex = parameterIndex ; } } } return maxParameterIndex ; } function getMetadataParameterLengthReducer ( selector , maxParameterIndex ) { return Math . max ( maxParameterIndex , getOwnMetadataMaxParameterIndex ( selector ) ) ; } param target param propertyKey param parameterIndex export function getOwnMetadataParameterLength ( target , propertyKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; return getOwnMetadataMaxParameterIndex ( createParameterDescriptor ( target , propertyKey , - 1 ) ) ; } param target param propertyKey param parameterIndex export function getMetadataParameterLength ( target , propertyKey ) { if ( ! isObject ( target ) ) throw new TypeError ( ) ; return walk ( createParameterDescriptor ( target , propertyKey , - 1 ) , hasOwnMember , getMetadataParameterLengthReducer , false , - 1 ) + 1 ; } function metadataDecorator ( descriptor , metadataKey , metadataValue ? ) ; function metadataDecorator ( descriptor , metadataKey , metadataValue ? ) ; function metadataDecorator ( descriptor , metadataKey , metadataValue ? ) ; function metadataDecorator ( descriptor , metadataKey , metadataValue ? ) { if ( ! isClass ( descriptor ) && ! isMember ( descriptor ) && ! isParameter ( descriptor ) ) throw new TypeError ( `'@metadata' is only supported on classes, members, and parameters.` ) ; const selector = descriptor . kind === "class" ? createObjectDescriptor ( descriptor . target ) : descriptor ; defineMetadata ( selector , metadataKey , metadataValue ) ; } param metadataKey param metadataValue export const metadata = Object . assign ( createDecoratorFactory ( metadataDecorator ) , { defineObjectMetadata , deleteObjectMetadata , hasOwnObjectMetadata , hasObjectMetadata , getOwnObjectMetadata , getObjectMetadata , getOwnObjectMetadataKeys , getObjectMetadataKeys , definePropertyMetadata , deletePropertyMetadata , hasOwnPropertyMetadata , hasPropertyMetadata , getOwnPropertyMetadata , getPropertyMetadata , getOwnPropertyMetadataKeys , getPropertyMetadataKeys , getOwnMetadataProperties , getMetadataProperties , defineParameterMetadata , deleteParameterMetadata , hasOwnParameterMetadata , hasParameterMetadata , getOwnParameterMetadata , getParameterMetadata , getOwnParameterMetadataKeys , getParameterMetadataKeys , getOwnMetadataParameterLength , getMetadataParameterLength , } ) ; export { metadata as Metadata } ; function walk < S extends MetadataSelector , U > ( selector , canGetValue , getValue , reduce , defaultValue ) ; function walk < U > ( selector , canGetValue , getValue , reduce , defaultValue ) { let current = selector . target ; while ( isObject ( current ) ) { selector = { ... selector } ; selector . target = current ; if ( canGetValue ( selector ) ) { defaultValue = getValue ( selector , defaultValue ) ; if ( ! reduce ) break ; } if ( selector . kind === "parameter" && hasOwnMember ( selector ) ) { break ; } current = Object . getPrototypeOf ( selector . target ) ; } return defaultValue ; } function addRange < T > ( set , values ) { for ( const value of values ) { set . add ( value ) ; } return set ; } function T ( ) { return true ; }