-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from integreat-io/feature/pipes
Feature/pipes
- Loading branch information
Showing
50 changed files
with
3,515 additions
and
4,514 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import test from 'ava' | ||
import { State } from '../types' | ||
|
||
import alt from './alt' | ||
|
||
// Helpers | ||
|
||
const getUser = (state: State) => ({ ...state, value: (state.value as any).user }) | ||
|
||
// Tests | ||
|
||
test('should set alt value when value is undefined', (t) => { | ||
const state = { | ||
root: { user: 'johnf' }, | ||
context: { user: 'johnf' }, | ||
value: undefined | ||
} | ||
const expected = { | ||
root: { user: 'johnf' }, | ||
context: { user: 'johnf' }, | ||
value: 'johnf' | ||
} | ||
|
||
const ret = alt(getUser)(state) | ||
|
||
t.deepEqual(ret, expected) | ||
}) | ||
|
||
test('should do nothing when value is set', (t) => { | ||
const state = { | ||
root: { user: 'johnf' }, | ||
context: { user: 'johnf' }, | ||
value: 'maryk' | ||
} | ||
const expected = { | ||
root: { user: 'johnf' }, | ||
context: { user: 'johnf' }, | ||
value: 'maryk' | ||
} | ||
|
||
const ret = alt(getUser)(state) | ||
|
||
t.deepEqual(ret, expected) | ||
}) | ||
|
||
test('should do nothing when onlyMapped is true', (t) => { | ||
const state = { | ||
root: { user: 'johnf' }, | ||
context: { user: 'johnf' }, | ||
value: undefined, | ||
onlyMapped: true | ||
} | ||
const expected = { | ||
root: { user: 'johnf' }, | ||
context: { user: 'johnf' }, | ||
value: undefined, | ||
onlyMapped: true | ||
} | ||
|
||
const ret = alt(getUser)(state) | ||
|
||
t.deepEqual(ret, expected) | ||
}) | ||
|
||
test('should treat string as path', (t) => { | ||
const state = { | ||
root: { user: 'johnf' }, | ||
context: { user: 'johnf' }, | ||
value: undefined | ||
} | ||
const expected = { | ||
root: { user: 'johnf' }, | ||
context: { user: 'johnf' }, | ||
value: 'johnf' | ||
} | ||
|
||
const ret = alt('user')(state) | ||
|
||
t.deepEqual(ret, expected) | ||
}) | ||
|
||
test('should treat array as map pipe', (t) => { | ||
const state = { | ||
root: { user: 'johnf' }, | ||
context: { user: 'johnf' }, | ||
value: undefined | ||
} | ||
const expected = { | ||
root: { user: 'johnf' }, | ||
context: { user: 'johnf' }, | ||
value: 'johnf' | ||
} | ||
|
||
const ret = alt(['user'])(state) | ||
|
||
t.deepEqual(ret, expected) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import * as mapAny from 'map-any' | ||
import { State, Data, MapFunction, MapDefinition } from '../types' | ||
import { setStateValue, getStateValue } from '../utils/stateHelpers' | ||
import { mapFunctionFromDef } from '../utils/definitionHelpers' | ||
|
||
const getOne = (context: Data | Data[], index?: number) => | ||
(typeof index === 'undefined' || !Array.isArray(context)) ? context : context[index] | ||
|
||
const getValueOrDefault = (state: State, runAlt: MapFunction) => (value: Data, index?: number) => | ||
(typeof value === 'undefined') | ||
? getStateValue(runAlt({ ...state, value: getOne(state.context, index) })) | ||
: value | ||
|
||
export default function alt (fn: MapDefinition): MapFunction { | ||
const runAlt = mapFunctionFromDef(fn) | ||
|
||
return (state: State) => (state.onlyMapped) | ||
? state | ||
: setStateValue( | ||
state, | ||
mapAny(getValueOrDefault(state, runAlt), state.value) | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import test from 'ava' | ||
import { MapFunction } from '../types' | ||
|
||
import { fwd, rev } from './directionals' | ||
|
||
// Helpers | ||
|
||
const upperCase = (str: string | any) => (typeof str === 'string') ? str.toUpperCase() : str | ||
const upper: MapFunction = (state) => ({ ...state, value: upperCase(state.value) }) | ||
|
||
// Tests -- forward | ||
|
||
test('should apply function when not rev', (t) => { | ||
const state = { | ||
root: { title: 'Entry 1' }, | ||
context: { title: 'Entry 1' }, | ||
value: 'Entry 1', | ||
rev: false | ||
} | ||
const expected = { | ||
root: { title: 'Entry 1' }, | ||
context: { title: 'Entry 1' }, | ||
value: 'ENTRY 1', | ||
rev: false | ||
} | ||
|
||
const ret = fwd(upper)(state) | ||
|
||
t.deepEqual(ret, expected) | ||
}) | ||
|
||
test('should not apply function when rev', (t) => { | ||
const state = { | ||
root: { title: 'Entry 1' }, | ||
context: { title: 'Entry 1' }, | ||
value: 'Entry 1', | ||
rev: true | ||
} | ||
const expected = { | ||
root: { title: 'Entry 1' }, | ||
context: { title: 'Entry 1' }, | ||
value: 'Entry 1', | ||
rev: true | ||
} | ||
|
||
const ret = fwd(upper)(state) | ||
|
||
t.deepEqual(ret, expected) | ||
}) | ||
|
||
test('should treat string as get path in fwd', (t) => { | ||
const state = { | ||
root: { title: 'Entry 1' }, | ||
context: { title: 'Entry 1' }, | ||
value: { title: 'Entry 1' }, | ||
rev: false | ||
} | ||
const expectedValue = 'Entry 1' | ||
|
||
const ret = fwd('title')(state) | ||
|
||
t.deepEqual(ret.value, expectedValue) | ||
}) | ||
|
||
// Tests -- reverse | ||
|
||
test('should apply function when rev', (t) => { | ||
const state = { | ||
root: { title: 'Entry 1' }, | ||
context: { title: 'Entry 1' }, | ||
value: 'Entry 1', | ||
rev: true | ||
} | ||
const expected = { | ||
root: { title: 'Entry 1' }, | ||
context: { title: 'Entry 1' }, | ||
value: 'ENTRY 1', | ||
rev: true | ||
} | ||
|
||
const ret = rev(upper)(state) | ||
|
||
t.deepEqual(ret, expected) | ||
}) | ||
|
||
test('should not apply function when fwd', (t) => { | ||
const state = { | ||
root: { title: 'Entry 1' }, | ||
context: { title: 'Entry 1' }, | ||
value: 'Entry 1', | ||
rev: false | ||
} | ||
const expected = { | ||
root: { title: 'Entry 1' }, | ||
context: { title: 'Entry 1' }, | ||
value: 'Entry 1', | ||
rev: false | ||
} | ||
|
||
const ret = rev(upper)(state) | ||
|
||
t.deepEqual(ret, expected) | ||
}) | ||
|
||
test('should treat string as get path in rev', (t) => { | ||
const state = { | ||
root: 'Entry 1', | ||
context: 'Entry 1', | ||
value: 'Entry 1', | ||
rev: true | ||
} | ||
const expectedValue = { title: 'Entry 1' } | ||
|
||
const ret = rev('title')(state) | ||
|
||
t.deepEqual(ret.value, expectedValue) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { MapDefinition, MapFunction } from '../types' | ||
import { mapFunctionFromDef } from '../utils/definitionHelpers' | ||
|
||
const applyInDirection = (def: MapDefinition, rev: boolean): MapFunction => { | ||
const fn = mapFunctionFromDef(def) | ||
return (state) => (rev ? state.rev : !state.rev) ? fn(state) : state | ||
} | ||
export function fwd (def: MapDefinition): MapFunction { | ||
return applyInDirection(def, false) | ||
} | ||
|
||
export function rev (def: MapDefinition): MapFunction { | ||
return applyInDirection(def, true) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import test from 'ava' | ||
|
||
import filter, { FilterFunction } from './filter' | ||
|
||
// Helpers | ||
|
||
const beginsWithA: FilterFunction = (str) => (typeof str === 'string') ? str.startsWith('A') : false | ||
|
||
// Tests | ||
|
||
test('should set value to undefined when filter returns false', (t) => { | ||
const state = { | ||
root: { title: 'Other entry' }, | ||
context: { title: 'Other entry' }, | ||
value: 'Other entry' | ||
} | ||
const expected = { | ||
root: { title: 'Other entry' }, | ||
context: { title: 'Other entry' }, | ||
value: undefined | ||
} | ||
|
||
const ret = filter(beginsWithA)(state) | ||
|
||
t.deepEqual(ret, expected) | ||
}) | ||
|
||
test('should not touch value when filter returns true', (t) => { | ||
const state = { | ||
root: { title: 'An entry' }, | ||
context: { title: 'An entry' }, | ||
value: 'An entry' | ||
} | ||
|
||
const ret = filter(beginsWithA)(state) | ||
|
||
t.deepEqual(ret, state) | ||
}) | ||
|
||
test('should remove values in array when filter returns false', (t) => { | ||
const state = { | ||
root: { users: ['John F', 'Andy'] }, | ||
context: { users: ['John F', 'Andy'] }, | ||
value: ['John F', 'Andy'] | ||
} | ||
const expected = { | ||
root: { users: ['John F', 'Andy'] }, | ||
context: { users: ['John F', 'Andy'] }, | ||
value: ['Andy'] | ||
} | ||
|
||
const ret = filter(beginsWithA)(state) | ||
|
||
t.deepEqual(ret, expected) | ||
}) | ||
|
||
test('should not touch value when filter is not a function', (t) => { | ||
const state = { | ||
root: { title: 'An entry' }, | ||
context: { title: 'An entry' }, | ||
value: 'An entry' | ||
} | ||
|
||
const ret = filter('notallowed' as any)(state) | ||
|
||
t.deepEqual(ret, state) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { compose, unless, always, ifElse, filter as filterR, identity } from 'ramda' | ||
import { MapFunction, Data, State } from '../types' | ||
import { getStateValue } from '../utils/stateHelpers' | ||
|
||
export interface FilterFunction { | ||
(data: Data): boolean | ||
} | ||
|
||
export default function filter (fn: FilterFunction): MapFunction { | ||
if (typeof fn !== 'function') { | ||
return identity | ||
} | ||
|
||
const runFilter = compose( | ||
ifElse( | ||
Array.isArray, | ||
filterR(fn), | ||
unless(fn, always(undefined)) | ||
), | ||
getStateValue | ||
) | ||
|
||
return (state: State) => ({ | ||
...state, | ||
value: runFilter(state) | ||
}) | ||
} |
Oops, something went wrong.