immutable.js
function create(defaults) {

    let props = Object.getOwnPropertyNames(defaults);

    /** Immutable class created from defaults.
     *
     */
    const immutableClass = class {

        /** Constructor.
         *
         * Can take a single object argument, in which case the properties of the object are copied over into
         * any matching default propertis that were defined in 'create'. Can also take normal arguments, in which
         * case the arguments are matched to the default properties in the order in which they were originally 
         * defined in the defaults object.
         */
        constructor() {
            debug('constructor', props, defaults, arguments);

            values = processArguments(props,arguments,defaults);

            // Otherwise assign arguments to properties in order
            for (let prop of props) {
                let value = values[prop]
                Object.defineProperty(this, prop, { value, enumerable: true, writable: false });
            }           
        }

        /** Merge a set of properties with the immutable object, returning a new immutable object
        *
        * @param props Properties to merge.
        * @returns a new immutable object of the same type as 'this'.
        */
        merge(props) {
            return new this.constructor(Object.assign({}, this, props));
        }

        /** Get the immutable property names
         *
         * An immutable object may legitimately have transient proprerties that are not part of the public
         * interface of the object. We therefore create a getImmutablePropertyNames static method that gets
         * the list of immutable properties names that is defined for this class.
         */
        static getImmutablePropertyNames() { return props; }

        /** Extends an immutable object, making a new immutable object.
         *
         * @param new_defaults additional properties for the extended object, plus default values for them.
         */
        static extend(new_defaults) { return extend(immutableClass, new_defaults)}
    };

    for (let prop of props) {
        let setterName = 'set' + prop.slice(0,1).toUpperCase() + prop.slice(1);
        immutableClass.prototype[setterName] = function(val) {
            debug(setterName, prop, val);
            return this.merge({ [prop] : val });
        };
    }

    return immutableClass;

}
function create(defaults) {

    let props = Object.getOwnPropertyNames(defaults);

    /** Immutable class created from defaults.
     *
     */
    const immutableClass = class {

        /** Constructor.
         *
         * Can take a single object argument, in which case the properties of the object are copied over into
         * any matching default propertis that were defined in 'create'. Can also take normal arguments, in which
         * case the arguments are matched to the default properties in the order in which they were originally 
         * defined in the defaults object.
         */
        constructor() {
            debug('constructor', props, defaults, arguments);

            values = processArguments(props,arguments,defaults);

            // Otherwise assign arguments to properties in order
            for (let prop of props) {
                let value = values[prop]
                Object.defineProperty(this, prop, { value, enumerable: true, writable: false });
            }           
        }

        /** Merge a set of properties with the immutable object, returning a new immutable object
        *
        * @param props Properties to merge.
        * @returns a new immutable object of the same type as 'this'.
        */
        merge(props) {
            return new this.constructor(Object.assign({}, this, props));
        }

        /** Get the immutable property names
         *
         * An immutable object may legitimately have transient proprerties that are not part of the public
         * interface of the object. We therefore create a getImmutablePropertyNames static method that gets
         * the list of immutable properties names that is defined for this class.
         */
        static getImmutablePropertyNames() { return props; }

        /** Extends an immutable object, making a new immutable object.
         *
         * @param new_defaults additional properties for the extended object, plus default values for them.
         */
        static extend(new_defaults) { return extend(immutableClass, new_defaults)}
    };

    for (let prop of props) {
        let setterName = 'set' + prop.slice(0,1).toUpperCase() + prop.slice(1);
        immutableClass.prototype[setterName] = function(val) {
            debug(setterName, prop, val);
            return this.merge({ [prop] : val });
        };
    }

    return immutableClass;

}
function create ( defaults ) { let props = Object . getOwnPropertyNames ( defaults ) ; /** Immutable class created from defaults.
     *
     */ const immutableClass = class { /** Constructor.
         *
         * Can take a single object argument, in which case the properties of the object are copied over into
         * any matching default propertis that were defined in 'create'. Can also take normal arguments, in which
         * case the arguments are matched to the default properties in the order in which they were originally 
         * defined in the defaults object.
         */ constructor ( ) { debug ( 'constructor' , props , defaults , arguments ) ; values = processArguments ( props , arguments , defaults ) ; // Otherwise assign arguments to properties in order for ( let prop of props ) { let value = values [ prop ] Object . defineProperty ( this , prop , { value , enumerable : true , writable : false } ) ; } } /** Merge a set of properties with the immutable object, returning a new immutable object
        *
        * @param props Properties to merge.
        * @returns a new immutable object of the same type as 'this'.
        */ merge ( props ) { return new this . constructor ( Object . assign ( { } , this , props ) ) ; } /** Get the immutable property names
         *
         * An immutable object may legitimately have transient proprerties that are not part of the public
         * interface of the object. We therefore create a getImmutablePropertyNames static method that gets
         * the list of immutable properties names that is defined for this class.
         */ static getImmutablePropertyNames ( ) { return props ; } /** Extends an immutable object, making a new immutable object.
         *
         * @param new_defaults additional properties for the extended object, plus default values for them.
         */ static extend ( new_defaults ) { return extend ( immutableClass , new_defaults ) } } ; for ( let prop of props ) { let setterName = 'set' + prop . slice ( 0 , 1 ) . toUpperCase ( ) + prop . slice ( 1 ) ; immutableClass . prototype [ setterName ] = function ( val ) { debug ( setterName , prop , val ) ; return this . merge ( { [ prop ] : val } ) ; } ; } return immutableClass ; }
Create an immutable class

The resulting class will have the supplied properties and defaults, a constructor, and setters
which return a copy of the instance they are applied to with the implied update in place.

Passing in { property: undefined } will ensure a setter is created for 'property' without creating a default.

@param defaults {Object} A set of key/value pairs used to create default properties for class instances.
@returns A class object with appropriate properties and setter methods.
Create an immutable class