import { pluralize , underscore } from "inflected" ; import { applyModelConfig , JSORMBase , ModelConfiguration , ModelConfigurationOptions , isModelClass , isModelInstance } from "./model" ; import { Attribute , AttributeOptions } from "./attribute" ; import { AssociationFactoryOpts , AssociationRecord , HasMany , HasOne , BelongsTo } from "./associations" ; import { config as envConfig , inBrowser } from "./util/env" ; import { logger } from "./logger" ; type ModelDecorator = < M extends typeof JSORMBase > ( target : M ) => M ; const ModelDecorator = ( config ? ) : ModelDecorator => { return < M extends typeof JSORMBase > ( target ) : M => { modelFactory ( target , config ) ; return target ; } ; } ; export const initModel = ( modelClass , config ? ) : void => { modelFactory ( modelClass , config ) ; } ; const modelFactory = < M extends typeof JSORMBase > ( ModelClass , config ? ) : void => { ensureModelInheritance ( ModelClass ) ; applyModelConfig ( ModelClass , config || { } ) ; if ( ! ModelClass . jsonapiType && ! ModelClass . isBaseClass ) { ModelClass . jsonapiType = pluralize ( underscore ( ModelClass . name ) ) ; if ( envConfig . productionTip && inBrowser ) { logger . warn ( `Inferring model jsonapiType as "${ ModelClass . jsonapiType }".\nYou should explicitly set this on your model if targeting a minified code bundle.` ) ; } } ModelClass . registerType ( ) ; } ; const AttrDecoratorFactory = ( configOrTarget ? , propertyKey ? , attrConfig ? ) : any => { let attrDefinition = new Attribute ( { name : propertyKey } ) ; const attrFunction = ( ModelClass , propKey ) : PropertyDescriptor => { ensureModelInheritance ( ModelClass ) ; if ( ! attrDefinition . name ) { attrDefinition . name = propKey ; } ModelClass . attributeList [ propKey ] = attrDefinition ; attrDefinition . apply ( ModelClass ) ; return attrDefinition . descriptor ( ) ; } ; if ( isModelClass ( configOrTarget ) || isModelInstance ( configOrTarget ) ) { if ( ! propertyKey ) { throw new Error ( "Must provide a propertyKey" ) ; } const target = configOrTarget ; if ( isModelClass ( target ) ) { if ( attrConfig ) { attrDefinition = new Attribute ( attrConfig ) ; } attrFunction ( target , propertyKey ) ; } else { return attrFunction ( < any > target . constructor , propertyKey ) ; } } else { if ( configOrTarget ) { attrDefinition = new Attribute ( configOrTarget ) ; } return ( target , propKey ) => { return attrFunction ( < any > target . constructor , propKey ) ; } ; } } ; const ensureModelInheritance = ( ModelClass ) => { if ( ModelClass . currentClass !== ModelClass ) { ModelClass . currentClass . inherited ( ModelClass ) ; } } ; type DecoratorFn = ( target : JSORMBase , propertyKey : string ) => void ; type DecoratorArgs < T extends JSORMBase > = AssociationFactoryOpts < T > | string | typeof JSORMBase ; const AssociationDecoratorFactoryBuilder = < T extends JSORMBase > ( AttrType ) => { const DecoratorFactory = ( targetOrConfig ? , propertyKey ? , optsOrType ? ) : any => { const extend = ( ModelClass ) : typeof JSORMBase => { ensureModelInheritance ( ModelClass ) ; return ModelClass ; } ; let opts ; const factoryFn = ( target , propKey ) => { if ( optsOrType === undefined ) { const inferredType = pluralize ( underscore ( propKey ) ) ; opts = { jsonapiType : inferredType } ; } else if ( typeof optsOrType === "string" ) { opts = { jsonapiType : optsOrType } ; } else if ( isModelClass ( optsOrType ) ) { opts = { type : optsOrType as any } ; } else { opts = { persist : optsOrType . persist , name : optsOrType . name } ; if ( typeof optsOrType . type === "string" ) { opts . jsonapiType = optsOrType . type ; } else { opts . type = optsOrType . type as any ; } } const attrDefinition = new AttrType ( opts ) ; if ( ! attrDefinition . name ) { attrDefinition . name = propKey ; } const ModelClass = extend ( < any > target . constructor ) ; ModelClass . attributeList [ propKey ] = attrDefinition ; attrDefinition . owner = target . constructor ; attrDefinition . apply ( ModelClass ) ; return attrDefinition . descriptor ( ) ; } ; if ( isModelClass ( targetOrConfig ) && propertyKey ) { const target = targetOrConfig ; factoryFn ( target . prototype , propertyKey ) ; } else { optsOrType = targetOrConfig ; return factoryFn ; } } ; return DecoratorFactory ; } ; const HasManyDecoratorFactory = AssociationDecoratorFactoryBuilder ( HasMany ) ; const HasOneDecoratorFactory = AssociationDecoratorFactoryBuilder ( HasOne ) ; const BelongsToDecoratorFactory = AssociationDecoratorFactoryBuilder ( BelongsTo ) ; export { ModelDecorator as Model , AttrDecoratorFactory as Attr , HasManyDecoratorFactory as HasMany , HasOneDecoratorFactory as HasOne , BelongsToDecoratorFactory as BelongsTo } ;