diff --git a/packages/core/src/lib/create-mapper/create-mapper.ts b/packages/core/src/lib/create-mapper/create-mapper.ts index e4c2c5b3a..e9a8c8efa 100644 --- a/packages/core/src/lib/create-mapper/create-mapper.ts +++ b/packages/core/src/lib/create-mapper/create-mapper.ts @@ -73,7 +73,8 @@ export function createMapper({ if ( (destinationObjOrOptions && ('beforeMap' in destinationObjOrOptions || - 'afterMap' in destinationObjOrOptions)) || + 'afterMap' in destinationObjOrOptions || + 'extraArguments' in destinationObjOrOptions)) || destinationObjOrOptions == null ) { return mapReturn( diff --git a/packages/core/src/lib/map/map.ts b/packages/core/src/lib/map/map.ts index 52bdb8ab7..0076a6901 100644 --- a/packages/core/src/lib/map/map.ts +++ b/packages/core/src/lib/map/map.ts @@ -11,6 +11,7 @@ import type { MapOptions, Mapper, Mapping, + MapWithArgumentsReturn, MapWithReturn, MemberMapReturn, } from '@automapper/types'; @@ -25,6 +26,7 @@ import { set, setMutate } from './set.util'; * @param {TSource} sourceObj - The sourceObject being used to map to destination * @param destination - destination meta key * @param {string} destinationMemberPath - the property path on the destination + * @param {Record} extraArguments * @param {Mapper} mapper - the mapper instance */ function mapMember = any>( @@ -32,6 +34,7 @@ function mapMember = any>( sourceObj: TSource, destination: unknown, destinationMemberPath: string, + extraArguments: Record, mapper: Mapper ) { let value: unknown; @@ -59,6 +62,12 @@ function mapMember = any>( destinationMemberPath ); break; + case TransformationType.MapWithArguments: + value = (mapFn as MapWithArgumentsReturn[MapFnClassId.fn])( + sourceObj, + extraArguments + ); + break; case TransformationType.MapDefer: value = mapMember( (mapFn as MapDeferReturn[MapFnClassId.fn])( @@ -67,6 +76,7 @@ function mapMember = any>( sourceObj, destination, destinationMemberPath, + extraArguments, mapper ); break; @@ -195,8 +205,11 @@ function map< const configuredKeys: string[] = []; // deconstruct MapOptions - const { beforeMap: mapBeforeAction, afterMap: mapAfterAction } = - options ?? {}; + const { + beforeMap: mapBeforeAction, + afterMap: mapAfterAction, + extraArguments, + } = options ?? {}; // Before Map // Do not run before map when in Map Array mode @@ -333,6 +346,7 @@ Original error: ${originalError}`; sourceObj, destination, destinationMemberPath, + extraArguments, mapper ) ); diff --git a/packages/core/src/lib/member-map-functions/index.ts b/packages/core/src/lib/member-map-functions/index.ts index 1ff633470..f12421f63 100644 --- a/packages/core/src/lib/member-map-functions/index.ts +++ b/packages/core/src/lib/member-map-functions/index.ts @@ -7,3 +7,4 @@ export * from './ignore'; export * from './null-substitution'; export * from './pre-condition'; export * from './map-defer'; +export * from './map-with-arguments'; diff --git a/packages/core/src/lib/member-map-functions/map-with-arguments.ts b/packages/core/src/lib/member-map-functions/map-with-arguments.ts new file mode 100644 index 000000000..f5965cc35 --- /dev/null +++ b/packages/core/src/lib/member-map-functions/map-with-arguments.ts @@ -0,0 +1,19 @@ +import type { + Dictionary, + MapWithArgumentsReturn, + SelectorReturn, +} from '@automapper/types'; +import { TransformationType } from '@automapper/types'; + +export function mapWithArguments< + TSource extends Dictionary = any, + TDestination extends Dictionary = any, + TSelectorReturn = SelectorReturn +>( + withArgumentsResolver: ( + source: TSource, + extraArguments: Record + ) => TSelectorReturn +): MapWithArgumentsReturn { + return [TransformationType.MapWithArguments, withArgumentsResolver]; +} diff --git a/packages/core/src/lib/member-map-functions/specs/map-with-arguments.spec.ts b/packages/core/src/lib/member-map-functions/specs/map-with-arguments.spec.ts new file mode 100644 index 000000000..ffffb9e02 --- /dev/null +++ b/packages/core/src/lib/member-map-functions/specs/map-with-arguments.spec.ts @@ -0,0 +1,27 @@ +import { mapWithArguments } from '@automapper/core'; +import { MapFnClassId, TransformationType } from '@automapper/types'; + +describe('MapWithArgumentsFunction', () => { + const withArgumentsResolver = ( + source: any, + extraArguments: { foo: string } + ) => source[extraArguments.foo]; + + it('should return correctly', () => { + const mapWithArgumentsFn = mapWithArguments(withArgumentsResolver); + expect(mapWithArgumentsFn).toBeTruthy(); + expect(mapWithArgumentsFn[MapFnClassId.type]).toEqual( + TransformationType.MapWithArguments + ); + expect(mapWithArgumentsFn[MapFnClassId.fn]).toBe(withArgumentsResolver); + }); + + it('should map correctly', () => { + const mapWithArgumentsFn = mapWithArguments(withArgumentsResolver); + const result = mapWithArgumentsFn[MapFnClassId.fn]( + { foo: 'this is awesome' }, + { foo: 'foo' } + ); + expect(result).toEqual('this is awesome'); + }); +});