1- const { Either, either, left, fromNullable } = require ( './src/either' )
2- const { List } = require ( './src/list' )
3-
4- const id = _ => _
5- const always = a => ( ) => a
1+ function id ( _ ) {
2+ return _
3+ }
64
75const DEFAULTS = {
86 types : { } ,
@@ -12,46 +10,37 @@ const DEFAULTS = {
1210 postFilters : [ ]
1311}
1412
15- /* --- Functional Utilities --- */
16- const map = fn => x => x . map ( fn )
17- const join = m => m . join ( )
18- // const chain = fn => m => m.chain(fn)
1913const compose = ( ...fns ) => ( res , ...args ) =>
2014 fns . reduceRight ( ( accum , next ) => next ( accum , ...args ) , res )
2115
22- const reduce = fn => zero => xs => xs . reduce ( fn , zero )
23- /* ---------------------------- */
24-
25- const split = d => s => s . split ( d )
26-
2716const createRootObj = compose (
28- either ( Object . create , Array ) ,
29- n => ( isNaN ( n ) ? left ( null ) : Either . of ( n ) ) ,
17+ n => ( isNaN ( n ) ? Object . create ( null ) : new Array ( n ) ) ,
3018 Number
3119)
3220
33- const handleArrays = _ => ( Array . isArray ( _ ) ? List . of ( _ ) : Either . of ( _ ) )
34-
35- const normalizeField = delimiter => m =>
36- fromNullable ( m )
37- . map ( m => m . indexOf ( delimiter ) > - 1 )
38- . map ( b => ( b ? m : m + delimiter + m ) )
39- . map ( split ( delimiter ) )
40-
41- const getMapSpec = delimiter => mapping =>
42- fromNullable ( mapping )
43- . map ( Array . isArray )
44- . map ( b => ( b ? Either . of ( mapping ) : left ( mapping ) ) )
45- . map (
46- either (
47- compose ( join , normalizeField ( delimiter ) ) ,
48- reduce ( ( spec , field ) =>
49- normalizeField ( delimiter ) ( field )
50- . map ( ( [ source , target ] ) => [ [ ...spec [ 0 ] , source ] , target ] )
51- . join ( )
52- ) ( [ [ ] , null ] )
53- )
21+ const normalizeField = delimiter => m => {
22+ if ( m . indexOf ( delimiter ) > - 1 ) {
23+ return m . split ( delimiter )
24+ }
25+
26+ return [ m , m ]
27+ }
28+
29+ const getMapSpec = delimiter => {
30+ const normalizer = normalizeField ( delimiter )
31+
32+ return mapping => {
33+ if ( ! Array . isArray ( mapping ) ) return normalizer ( mapping )
34+
35+ return mapping . reduce (
36+ ( spec , field ) => {
37+ const [ source , target ] = normalizer ( field )
38+ return [ [ ...spec [ 0 ] , source ] , target ]
39+ } ,
40+ [ [ ] , null ]
5441 )
42+ }
43+ }
5544
5645const normalizeMapping = mapping =>
5746 typeof mapping === 'string' ? { field : mapping } : mapping
@@ -63,67 +52,58 @@ const getMappingFilter = (type, types) => {
6352 return id
6453}
6554
66- const getKey = reduce ( ( accum , k ) => ( accum ? accum [ k ] : undefined ) )
67-
68- const get = ( key , delimiter = DEFAULTS . objDelimiter ) => obj =>
69- compose (
70- either ( always ( obj ) , getKey ( obj ) ) ,
71- map ( split ( delimiter ) ) ,
72- fromNullable
73- ) ( key )
74-
75- const setKey = value =>
76- reduce ( ( accum , key , i , array ) => {
77- if ( i === array . length - 1 ) accum [ key ] = value
78- else if ( ! accum [ key ] ) accum [ key ] = createRootObj ( array [ i + 1 ] )
79- return accum [ key ]
80- } )
81-
82- const assign = ( key , delimiter = DEFAULTS . objDelimiter ) => ( obj , value ) =>
83- compose (
84- always ( obj ) ,
85- either ( id , setKey ( value ) ( obj ) ) ,
86- map ( split ( delimiter ) ) ,
87- fromNullable
88- ) ( key )
55+ const get = ( key , delimiter = DEFAULTS . objDelimiter ) => {
56+ if ( key == null ) return id
57+
58+ const spec = key . split ( delimiter )
59+
60+ return obj => spec . reduce ( ( a , k ) => ( a ? a [ k ] : undefined ) , obj )
61+ }
62+
63+ const assign = ( key , delimiter = DEFAULTS . objDelimiter ) => {
64+ if ( key == null ) return id
65+
66+ const spec = key . split ( delimiter )
67+ return ( obj , value ) => {
68+ spec . reduce ( ( accum , key , i , array ) => {
69+ if ( i === array . length - 1 ) accum [ key ] = value
70+ else if ( ! accum [ key ] ) accum [ key ] = createRootObj ( array [ i + 1 ] )
71+ return accum [ key ]
72+ } , obj )
73+ return obj
74+ }
75+ }
8976
9077class Mapper {
9178 constructor ( options ) {
9279 this . config = Object . assign ( { } , DEFAULTS , options )
80+ this . getMapSpec = getMapSpec ( this . config . mapDelimiter )
9381 }
9482
9583 map ( mappings , curr , next = Object . create ( null ) ) {
96- return mappings . map ( normalizeMapping ) . reduce (
97- ( accum , mapping ) =>
98- fromNullable ( mapping . field )
99- . chain ( getMapSpec ( this . config . mapDelimiter ) )
100- . chain ( ( [ sourceField , targetField ] ) =>
101- Either . of ( sourceField )
102- . map ( handleArrays )
103- . map ( map ( field => get ( field , this . config . objDelimiter ) ( curr ) ) )
104- . map ( join )
105- . map ( _ =>
106- compose (
107- /* End user-land transforms */
108- ...this . config . postFilters ,
109- getMappingFilter ( mapping . type , this . config . types ) ,
110- ...this . config . preFilters
111- /* Begin user-land transforms */
112- ) ( _ , mapping , this . config , curr , accum )
113- )
114- . map ( fromNullable )
115- . chain (
116- either (
117- always ( accum ) ,
118- assign ( targetField , this . config . objDelimiter ) . bind (
119- this ,
120- accum
121- )
122- )
123- )
124- ) ,
125- next
126- )
84+ return mappings . map ( normalizeMapping ) . reduce ( ( accum , mapping ) => {
85+ const [ sourceField , targetField ] = this . getMapSpec ( mapping . field )
86+
87+ let value
88+ const fn = field => get ( field , this . config . objDelimiter ) ( curr )
89+ if ( Array . isArray ( sourceField ) ) {
90+ value = sourceField . map ( fn )
91+ } else {
92+ value = fn ( sourceField )
93+ }
94+
95+ value = compose (
96+ ...this . config . postFilters ,
97+ getMappingFilter ( mapping . type , this . config . types ) ,
98+ ...this . config . preFilters
99+ ) ( value , mapping , this . config , curr , accum )
100+
101+ if ( value === undefined ) {
102+ return accum
103+ }
104+
105+ return assign ( targetField , this . config . objDelimiter ) ( accum , value )
106+ } , next )
127107 }
128108}
129109
0 commit comments