import * as assert from 'assert' ; import * as _ from '../src/Lens' ; import { pipe } from 'fp-ts/lib/pipeable' ; import * as O from 'fp-ts/lib/Option' ; import * as A from 'fp-ts/lib/ReadonlyArray' ; import * as T from '../src/Traversal' ; import * as Op from '../src/Optional' ; import * as Id from 'fp-ts/lib/Identity' ; import * as U from './util' ; import { ReadonlyRecord } from 'fp-ts/lib/ReadonlyRecord' ; import { ReadonlyNonEmptyArray } from 'fp-ts/lib/ReadonlyNonEmptyArray' ; describe ( 'Lens' , ( ) => { describe ( 'pipeables' , ( ) => { it ( 'imap' , ( ) => { interface S { readonly a : number ; } const sa = pipe ( _ . id < S > ( ) , _ . imap ( ( s ) => s . a , ( a ) => ( { a } ) ) ) ; U . deepStrictEqual ( sa . get ( { a : 1 } ) , 1 ) ; U . deepStrictEqual ( sa . set ( 2 ) ( { a : 1 } ) , { a : 2 } ) ; } ) ; } ) ; it ( 'compose' , ( ) => { interface S { readonly a : A ; } interface A { readonly b : number ; } const sa = pipe ( _ . id < S > ( ) , _ . prop ( 'a' ) ) ; const ab = pipe ( _ . id < A > ( ) , _ . prop ( 'b' ) ) ; const sb = _ . Category . compose ( ab , sa ) ; U . deepStrictEqual ( sb . get ( { a : { b : 1 } } ) , 1 ) ; U . deepStrictEqual ( sb . set ( 2 ) ( { a : { b : 1 } } ) , { a : { b : 2 } } ) ; } ) ; it ( 'composeTraversal' , ( ) => { interface S { readonly a : ReadonlyArray < number > ; } const sa = pipe ( _ . id < S > ( ) , _ . prop ( 'a' ) ) ; const ab = T . fromTraversable ( A . readonlyArray ) < number > ( ) ; const sb = pipe ( sa , _ . composeTraversal ( ab ) ) ; U . deepStrictEqual ( sb . modifyF ( Id . identity ) ( ( n ) => n * 2 ) ( { a : [ 1 , 2 , 3 ] } ) , { a : [ 2 , 4 , 6 ] } ) ; } ) ; it ( 'id' , ( ) => { interface S { readonly a : number ; } const ss = _ . id < S > ( ) ; const s = { a : 1 } ; U . deepStrictEqual ( ss . get ( s ) , s ) ; U . deepStrictEqual ( ss . set ( s ) ( s ) , s ) ; } ) ; it ( 'fromNullable' , ( ) => { interface S { readonly a ? : number ; } const sa = pipe ( _ . id < S > ( ) , _ . prop ( 'a' ) , _ . fromNullable ) ; const s = { a : 1 } ; U . deepStrictEqual ( sa . getOption ( s ) , O . some ( 1 ) ) ; U . deepStrictEqual ( sa . getOption ( { } ) , O . none ) ; assert . strictEqual ( sa . set ( 1 ) ( s ) , s ) ; } ) ; it ( 'modify' , ( ) => { interface S { readonly a : number ; } const sa = pipe ( _ . id < S > ( ) , _ . prop ( 'a' ) ) ; const f = pipe ( sa , _ . modify ( ( a ) => a * 2 ) ) ; U . deepStrictEqual ( f ( { a : 1 } ) , { a : 2 } ) ; } ) ; it ( 'prop' , ( ) => { interface S { readonly a : { readonly b : number ; } ; } const sa = pipe ( _ . id < S > ( ) , _ . prop ( 'a' ) , _ . prop ( 'b' ) ) ; const s = { a : { b : 1 } } ; assert . strictEqual ( sa . get ( s ) , 1 ) ; U . deepStrictEqual ( sa . set ( 2 ) ( s ) , { a : { b : 2 } } ) ; assert . strictEqual ( sa . set ( 1 ) ( s ) , s ) ; } ) ; it ( 'props' , ( ) => { interface S { readonly a : { readonly b : string ; readonly c : number ; readonly d : boolean ; } ; } const sa = pipe ( _ . id < S > ( ) , _ . prop ( 'a' ) , _ . props ( 'b' , 'c' ) ) ; const s = { a : { b : 'b' , c : 1 , d : true } } ; U . deepStrictEqual ( sa . get ( s ) , { b : 'b' , c : 1 } ) ; U . deepStrictEqual ( sa . set ( { b : 'b' , c : 2 } ) ( s ) , { a : { b : 'b' , c : 2 , d : true } } ) ; assert . strictEqual ( sa . set ( { b : 'b' , c : 1 } ) ( s ) , s ) ; } ) ; it ( 'component' , ( ) => { interface S { readonly a : readonly [ string , number ] ; } const sa = pipe ( _ . id < S > ( ) , _ . prop ( 'a' ) , _ . component ( 1 ) ) ; const s = { a : [ 'a' , 1 ] } ; assert . strictEqual ( sa . get ( s ) , 1 ) ; U . deepStrictEqual ( sa . set ( 2 ) ( s ) , { a : [ 'a' , 2 ] } ) ; assert . strictEqual ( sa . set ( 1 ) ( s ) , s ) ; } ) ; it ( 'index' , ( ) => { interface S { readonly a : ReadonlyArray < number > ; } const optional = pipe ( _ . id < S > ( ) , _ . prop ( 'a' ) , _ . index ( 0 ) ) ; U . deepStrictEqual ( optional . getOption ( { a : [ ] } ) , O . none ) ; U . deepStrictEqual ( optional . getOption ( { a : [ 1 ] } ) , O . some ( 1 ) ) ; U . deepStrictEqual ( optional . set ( 2 ) ( { a : [ ] } ) , { a : [ ] } ) ; U . deepStrictEqual ( optional . set ( 2 ) ( { a : [ 1 ] } ) , { a : [ 2 ] } ) ; const empty = { a : [ ] } ; const full = { a : [ 1 ] } ; assert . strictEqual ( optional . set ( 1 ) ( empty ) , empty ) ; assert . strictEqual ( optional . set ( 1 ) ( full ) , full ) ; } ) ; it ( 'indexNonEmpty' , ( ) => { interface S { readonly a : ReadonlyNonEmptyArray < number > ; } const optional = pipe ( _ . id < S > ( ) , _ . prop ( 'a' ) , _ . indexNonEmpty ( 1 ) ) ; U . deepStrictEqual ( optional . getOption ( { a : [ 1 ] } ) , O . none ) ; U . deepStrictEqual ( optional . getOption ( { a : [ 1 , 2 ] } ) , O . some ( 2 ) ) ; U . deepStrictEqual ( optional . set ( 3 ) ( { a : [ 1 ] } ) , { a : [ 1 ] } ) ; U . deepStrictEqual ( optional . set ( 3 ) ( { a : [ 1 , 2 ] } ) , { a : [ 1 , 3 ] } ) ; const full = { a : [ 1 , 2 ] } ; assert . strictEqual ( optional . set ( 2 ) ( full ) , full ) ; } ) ; it ( 'key' , ( ) => { interface S { readonly a : ReadonlyRecord < string , number > ; } const sa = pipe ( _ . id < S > ( ) , _ . prop ( 'a' ) , _ . key ( 'k' ) ) ; const empty = { a : { } } ; const full = { a : { k : 1 , j : 2 } } ; U . deepStrictEqual ( sa . getOption ( empty ) , O . none ) ; U . deepStrictEqual ( sa . getOption ( full ) , O . some ( 1 ) ) ; U . deepStrictEqual ( sa . set ( 2 ) ( full ) , { a : { k : 2 , j : 2 } } ) ; assert . strictEqual ( sa . set ( 2 ) ( empty ) , empty ) ; assert . strictEqual ( sa . set ( 1 ) ( full ) , full ) ; } ) ; it ( 'traverse' , ( ) => { type S = ReadonlyArray < string > ; const sa = pipe ( _ . id < S > ( ) , _ . traverse ( A . readonlyArray ) ) ; const modify = pipe ( sa , T . modify ( ( s ) => s . toUpperCase ( ) ) ) ; U . deepStrictEqual ( modify ( [ 'a' ] ) , [ 'A' ] ) ; } ) ; it ( 'compose' , ( ) => { interface S { readonly a : A ; } interface A { readonly b : number ; } const sa = pipe ( _ . id < S > ( ) , _ . prop ( 'a' ) ) ; const ab = pipe ( _ . id < A > ( ) , _ . prop ( 'b' ) ) ; const sb = pipe ( sa , _ . compose ( ab ) ) ; U . deepStrictEqual ( sb . get ( { a : { b : 1 } } ) , 1 ) ; U . deepStrictEqual ( sb . set ( 2 ) ( { a : { b : 1 } } ) , { a : { b : 2 } } ) ; } ) ; it ( 'composeOptional' , ( ) => { interface S { readonly a : string ; } const sa = pipe ( _ . id < S > ( ) , _ . prop ( 'a' ) ) ; const ab = Op . optional ( ( s ) => ( s . length > 0 ? O . some ( s [ 0 ] ) : O . none ) , ( a ) => ( s ) => ( s . length > 0 ? a + s . substring ( 1 ) : s ) ) ; const sb = pipe ( sa , _ . composeOptional ( ab ) ) ; U . deepStrictEqual ( sb . getOption ( { a : '' } ) , O . none ) ; U . deepStrictEqual ( sb . getOption ( { a : 'ab' } ) , O . some ( 'a' ) ) ; U . deepStrictEqual ( sb . set ( 'c' ) ( { a : '' } ) , { a : '' } ) ; U . deepStrictEqual ( sb . set ( 'c' ) ( { a : 'ab' } ) , { a : 'cb' } ) ; } ) ; it ( 'atKey' , ( ) => { type S = ReadonlyRecord < string , number > ; const sa = pipe ( _ . id < S > ( ) , _ . atKey ( 'a' ) ) ; U . deepStrictEqual ( sa . get ( { a : 1 } ) , O . some ( 1 ) ) ; U . deepStrictEqual ( sa . set ( O . some ( 2 ) ) ( { a : 1 , b : 2 } ) , { a : 2 , b : 2 } ) ; U . deepStrictEqual ( sa . set ( O . some ( 1 ) ) ( { b : 2 } ) , { a : 1 , b : 2 } ) ; U . deepStrictEqual ( sa . set ( O . none ) ( { a : 1 , b : 2 } ) , { b : 2 } ) ; } ) ; it ( 'filter' , ( ) => { interface S { readonly a : number ; } const sa = pipe ( _ . id < S > ( ) , _ . prop ( 'a' ) , _ . filter ( ( n ) => n > 0 ) ) ; U . deepStrictEqual ( sa . getOption ( { a : 1 } ) , O . some ( 1 ) ) ; U . deepStrictEqual ( sa . getOption ( { a : - 1 } ) , O . none ) ; U . deepStrictEqual ( sa . set ( 2 ) ( { a : 1 } ) , { a : 2 } ) ; U . deepStrictEqual ( sa . set ( 2 ) ( { a : - 1 } ) , { a : - 1 } ) ; } ) ; it ( 'findFirst' , ( ) => { type S = ReadonlyArray < number > ; const optional = pipe ( _ . id < S > ( ) , _ . findFirst ( ( n ) => n > 0 ) ) ; U . deepStrictEqual ( optional . getOption ( [ ] ) , O . none ) ; U . deepStrictEqual ( optional . getOption ( [ - 1 , - 2 , - 3 ] ) , O . none ) ; U . deepStrictEqual ( optional . getOption ( [ - 1 , 2 , - 3 ] ) , O . some ( 2 ) ) ; U . deepStrictEqual ( optional . set ( 3 ) ( [ ] ) , [ ] ) ; U . deepStrictEqual ( optional . set ( 3 ) ( [ - 1 , - 2 , - 3 ] ) , [ - 1 , - 2 , - 3 ] ) ; U . deepStrictEqual ( optional . set ( 3 ) ( [ - 1 , 2 , - 3 ] ) , [ - 1 , 3 , - 3 ] ) ; U . deepStrictEqual ( optional . set ( 4 ) ( [ - 1 , - 2 , 3 ] ) , [ - 1 , - 2 , 4 ] ) ; } ) ; it ( 'findFirstNonEmpty' , ( ) => { type S = ReadonlyNonEmptyArray < number > ; const optional = pipe ( _ . id < S > ( ) , _ . findFirstNonEmpty ( ( n ) => n > 0 ) ) ; U . deepStrictEqual ( optional . getOption ( [ - 1 , - 2 , - 3 ] ) , O . none ) ; U . deepStrictEqual ( optional . getOption ( [ - 1 , 2 , - 3 ] ) , O . some ( 2 ) ) ; U . deepStrictEqual ( optional . set ( 3 ) ( [ - 1 , - 2 , - 3 ] ) , [ - 1 , - 2 , - 3 ] ) ; U . deepStrictEqual ( optional . set ( 3 ) ( [ - 1 , 2 , - 3 ] ) , [ - 1 , 3 , - 3 ] ) ; U . deepStrictEqual ( optional . set ( 4 ) ( [ - 1 , - 2 , 3 ] ) , [ - 1 , - 2 , 4 ] ) ; } ) ; it ( 'modifyF' , ( ) => { interface S { readonly a : number ; } const sa = pipe ( _ . id < S > ( ) , _ . prop ( 'a' ) ) ; const f = pipe ( sa , _ . modifyF ( O . option ) ( ( n ) => ( n > 0 ? O . some ( n * 2 ) : O . none ) ) ) ; U . deepStrictEqual ( f ( { a : 1 } ) , O . some ( { a : 2 } ) ) ; U . deepStrictEqual ( f ( { a : - 1 } ) , O . none ) ; } ) ; } ) ;