elm-types Strawman

import t from 'elm-types';

const AddTodo = t.Constructor('AddTodo', [t.String]);
const RemoveTodo = t.Constructor('AddTodo', [t.String]);
const Action = t.Union('Action', [AddTodo]);
const Todo = t.Record('Todo', {
    name: t.String,
    completed: t.Bool
});
const Model = t.Record('Model', {
    todos: t.List('todos', Todo)
});

// Throws if function is not passed correct parameter types
const update = t.Function('update', [Model, Action, Model], (state, action) =>
    // Throws if last object is not exaustive
    t.case(action, Action, {
        [AddTodo]: add => ({
            ...state,
            todos: [...state.todos, Todo(add, false)]
        }),
        [RemoveTodo]: remove => ({
            ...state,
            todos: state.todos.filter(todo => todo.name === remove)
        })
    });
);

const store = createStore(update, Model([]));

const App = ({ todos }) => (
    

Todo List

    {todos.map(todo => (
  • store.dispatch(RemoveTodo(todo.name))}> {todo.name}
  • ))}
); const AppProps = t.Record('AppProps', { todos: t.List('todos', Todo) }); App.propTypes = t.PropTypes(AppProps); render( , document.getElementById('app') );

flatten two ways

function flatten(source, acc = []) {
    if (source.length === 0) return acc;

    const [head, ...tail] = source;

    return flatten(tail, [...acc, ...(Array.isArray(head) ? flatten(head) : [head])]);
}

console.log(flatten([1,2,[3,4,5,[6,7],8,[9]],10]));
import * as R from 'ramda';

const flatten = R.ifElse(
    R.propSatisfies(R.equals(0), 'length'),
    R.flip(R.identity),
    R.converge((source, acc = []) => flatten(source, acc), [
	    R.tail,
        R.useWith(R.flip(R.concat), [
	        R.pipe(R.head, R.ifElse(Array.isArray, head => flatten(head, []), R.of)),
	        R.identity
        ])
    ])
);

console.log(flatten([1,2,[3,4,5,[6,7],8,[9]],10], []));

Arrow function problems

function foo(ddb) {
  return {
    listTables: (params = {}, cb = idFunc) => {
      const self = this
      let currentList = params.currentList || []
      
      return toPromise(ddb, ddb.listTables, omit(params, 'currentList'), cb)
        .then(r => {
          console.log('LISTTABLES result', r)
          currentList = currentList.concat(r.TableNames || [])
          
          if (!r.LastEvaluatedTableName || r.TableNames.length === 0) {
            return { ...r, TableNames: currentList }
          }

          return self.listTables({   // <- Fails here
              ...params,
              currentList,
              ExclusiveStartTableName: r.LastEvaluatedTableName,
            }, cb)
        })
    }
  }
}
class MyClass {
  myMethod = () => {
    // ...code
  }
}

Brookjs components strawman proposal

import { h, component } from 'brookjs'
import { editClick } from '../actions'

// Changes only occur when bound to a stream
export default component({
    render: props$ => (
        
  • {/* Text changes when a value is emitted. */}

    {props$.map(props => props.text)}

    {/* Maps a stream of events to actions. */}
  • ) })
    import { h, component } from 'brookjs'
    import TodoItem from './TodoItem'
    
    export default component({
        render: props$ => (
            

    My Todos

    {/** * `order` provides sequence todos should appear * `dict` provides a performant instance lookup */}
      {props$.map(todos => todos.order.map(key => ( todos.dict[key])} key={key} preplug={instance$ => instance$.map(action => ({ ...action, meta: { key } })} /> )))}
    ) })
    import { h, component } from 'brookjs'
    import TodoList from './TodoList'
    
    export default component({
        render: props$ => (
            

    Todo App

    {/** * Individual attributes respond to observables * Performance optimized inline */} props.editing).skipDuplicates()} onInput={event$ => event$.map(event => editTodo(event.target.value))} /> props.todos)} />
    ) })
    import { createStore, applyMiddleware } from 'redux'
    import { h, observeDelta, Kefir } from brookjs
    import { App } from './components'
    import { selectProps } from './selectors'
    
    const store = createStore(
        (state, action) => state, // reducer
        window.__INITIAL_STATE__ || {},
        applyMiddleware(observeDelta(
            /* register deltas here */
        )
    )
    const state$ = Kefir.fromESObservable(store)
    
    /**
     * `mount` thus takes the DOM to mount
     * and the element to bind it to, and
     * returns a stream. Note that because
     * of how streams work, nothing happens
     * until the stream is observed.
     */
    const view$ = mount(
        ,
        document.getElementById('app')
    )
     
    view$.observe(store.dispatch)
    import { h, component, list } from 'brookjs'
    import TodoItem from './TodoItem'
    
    export default component({
        render: props$ => (
            

    My Todos

      {/* Must be a stream of objects with `order` & `dict` */} {list(props$, (props$, key) => ( instance$.map(action => ({ ...action, meta: { key } })} /> )}
    ) })
    import { createStore, applyMiddleware } from 'redux'
    import { h, observeDelta, Kefir } from brookjs
    import { App } from './components'
    import { selectProps } from './selectors'
    
    const el = document.getElementById('app')
    
    const store = createStore(
        (state, action) => state,
        window.__INITIAL_STATE__ || {},
        applyMiddleware(observeDelta(
            /* register deltas here */
            domDelta({ el, selectProps, view: App })
        )
    )
    
    // Everything is bound to the store immediately,
    // but an init action makes sure everything waits
    // until the store is fully instantiated.
    store.dispatch(init())

    Point-Free Style – Functional Light JS v2 from Front-End Masters

    function output(txt) {
    	console.log(txt);
    }
    
    function printIf(predicate) {
    	return function(msg) {
    		if (predicate(msg)) {
    			output(msg);
    		}
    	};
    }
    
    function isShortEnough(str) {
    	return str.length <= 5;
    }
    
    function isLongEnough(str) {
    	return !isShortEnough(str);
    }
    
    var msg1 = "Hello";
    var msg2 = msg1 + " World";
    
    printIf(isShortEnough)(msg1);		// Hello
    printIf(isShortEnough)(msg2);
    printIf(isLongEnough)(msg1);
    printIf(isLongEnough)(msg2);		// Hello World
    const output = console.log.bind(console);
    const when = func => pred => val => {
      if (predicate(val)) {
        func(val);
      }
    };
    const not = func => val => !func(val);
    const printIf = when(output);
    const isShortEnough = str => str.length <= 5;
    const isLongEnough = not(isShortEnough);

    Simple Path

    const getPath = (path, target) =>
        path.split('.')
            .reduce((value, key) => value[key], target);
    
    // Usage
    const path = 'a.b.c';
    const target = {
        a: {
            b: {
                c: true
            }
        }
    };
    
    assert(true === getPath(path, target));

    Removed brookjs Actions

    /**
     * Value change Action type.
     *
     * @type {string}
     */
    export const VALUE_CHANGE = 'VALUE_CHANGE';
    
    /**
     * Create a new Value Change action.
     *
     * @param {string} value - Target value.
     * @returns {Action} Value Change action object.
     */
    export function valueEventAction(value) {
        return {
            type: VALUE_CHANGE,
            payload: { value }
        };
    }
    
    /**
     * Field focus event action type.
     *
     * @type {string}
     */
    export const FIELD_FOCUS = 'FIELD_FOCUS';
    
    /**
     * Create a FIELD_FOCUS action object.
     *
     * @param {string} name - Field name.
     * @returns {Action} FIELD_FOCUS action.
     */
    export function fieldFocusAction(name) {
        return {
            type: FIELD_FOCUS,
            payload: { name }
        };
    }
    
    /**
     * Checked change constant.
     *
     * @type {string}
     */
    export const CHECKED_CHANGE = 'CHECKED_CHANGE';
    
    /**
     * Create a new Checked Change action.
     *
     * @param {boolean} value - Target checked.
     * @returns {Action} Checked Change action object.
     */
    export function checkedEventAction(value) {
        return {
            type: CHECKED_CHANGE,
            payload: { value }
        };
    }
    
    /**
     * Click event Action type.
     *
     * @type {string}
     */
    export const CLICK = 'CLICK';
    
    /**
     * Create a new Clicked Action
     *
     * @returns {Action} Clicked action object.
     */
    export function clickedEventAction() {
        return { type: CLICK };
    }

    Observable Rendering

    import Kefir from 'kefir';
    
    export default function EditorComponent(el, props$) {
        const keyup$ = Kefir.fromEvents(el, 'keyup');
        const keydown$ = Kefir.fromEvents(el, 'keydown');
    
        return props$.sampledBy(keyup$.debounce(150))
            .flatMapLatest(props =>
                createRenderStream(props).takeUntil(keydown$)
            );
    
        function createRenderStream(props) {
            return Kefir.stream(emitter => {
                const loop = requestAnimationFrame(() => {
                    // Update the element
                    emitter.end();
                });
    
                return () => cancelAnimationFrame(loop);
            });
        }
    };