lib/templateUtils.js
function(template, delta) {

    assert.ok(Array.isArray(template), "'template' is not an array");
    assert.ok(Array.isArray(delta), "'delta' is not an array");

    /*
     *  This merge step is inefficient O(n*m) but we are assuming small arrays
     *  and 'delta' typically smaller than 'template'.
     *
     *  A 'delta' operation could merge with another component in 'template'
     *  with the same name, it could delete an existing entry if the 'module'
     *  key is null, or it could insert a new entry in the array.
     *  The insertion point of a new entry is just after the previous
     *  operation target. If the first operation in 'delta' is a new entry it
     *  becomes the first element.
     *
     *  Note that 'delta' is not sorted and it could contain duplicates. This
     * allow us to change the order in the original list. For example,
     *  if template is [A|B|...], and we want to swap B and A, we can add these
     * three operations in delta:
     *
     *     Remove A (assign null to A's module)
     *     Touch B (just have an entry with B's name that won't change B)
     *     Add A with the original A's values (inserted after B)
     *
     */

    var findEntry = function(result, name, lastOp) {
        return result.some(function(x, i) {
            if (x.name === name) {
                lastOp.index = i;
                return true;
            } else {
                return false;
            }
        });
    };

    var deleteEntry = function(result, name, lastOp) {
        if (findEntry(result, name, lastOp)) {
            result.splice(lastOp.index, 1);
            lastOp.index = lastOp.index -1;
        }
    };

    var insertEntry = function(result, entry, lastOp) {
        // splice prepends, and we want after
        lastOp.index = lastOp.index + 1;
        result.splice(lastOp.index, 0, entry);
    };

    var result = myUtils.deepClone(template);
    var lastOp = {index: -1};
    delta.forEach(function(x) {
        if (x.module === null) {
            deleteEntry(result, x.name, lastOp);
        } else if (findEntry(result, x.name, lastOp)) {
            result[lastOp.index] = mergeObj(result[lastOp.index], x, false);
        } else {
            insertEntry(result, myUtils.deepClone(x), lastOp);
        }
    });
    return result;
}
function(template, delta) {

    assert.ok(Array.isArray(template), "'template' is not an array");
    assert.ok(Array.isArray(delta), "'delta' is not an array");

    /*
     *  This merge step is inefficient O(n*m) but we are assuming small arrays
     *  and 'delta' typically smaller than 'template'.
     *
     *  A 'delta' operation could merge with another component in 'template'
     *  with the same name, it could delete an existing entry if the 'module'
     *  key is null, or it could insert a new entry in the array.
     *  The insertion point of a new entry is just after the previous
     *  operation target. If the first operation in 'delta' is a new entry it
     *  becomes the first element.
     *
     *  Note that 'delta' is not sorted and it could contain duplicates. This
     * allow us to change the order in the original list. For example,
     *  if template is [A|B|...], and we want to swap B and A, we can add these
     * three operations in delta:
     *
     *     Remove A (assign null to A's module)
     *     Touch B (just have an entry with B's name that won't change B)
     *     Add A with the original A's values (inserted after B)
     *
     */

    var findEntry = function(result, name, lastOp) {
        return result.some(function(x, i) {
            if (x.name === name) {
                lastOp.index = i;
                return true;
            } else {
                return false;
            }
        });
    };

    var deleteEntry = function(result, name, lastOp) {
        if (findEntry(result, name, lastOp)) {
            result.splice(lastOp.index, 1);
            lastOp.index = lastOp.index -1;
        }
    };

    var insertEntry = function(result, entry, lastOp) {
        // splice prepends, and we want after
        lastOp.index = lastOp.index + 1;
        result.splice(lastOp.index, 0, entry);
    };

    var result = myUtils.deepClone(template);
    var lastOp = {index: -1};
    delta.forEach(function(x) {
        if (x.module === null) {
            deleteEntry(result, x.name, lastOp);
        } else if (findEntry(result, x.name, lastOp)) {
            result[lastOp.index] = mergeObj(result[lastOp.index], x, false);
        } else {
            insertEntry(result, myUtils.deepClone(x), lastOp);
        }
    });
    return result;
}
function ( template , delta ) { assert . ok ( Array . isArray ( template ) , "'template' is not an array" ) ; assert . ok ( Array . isArray ( delta ) , "'delta' is not an array" ) ; /*
     *  This merge step is inefficient O(n*m) but we are assuming small arrays
     *  and 'delta' typically smaller than 'template'.
     *
     *  A 'delta' operation could merge with another component in 'template'
     *  with the same name, it could delete an existing entry if the 'module'
     *  key is null, or it could insert a new entry in the array.
     *  The insertion point of a new entry is just after the previous
     *  operation target. If the first operation in 'delta' is a new entry it
     *  becomes the first element.
     *
     *  Note that 'delta' is not sorted and it could contain duplicates. This
     * allow us to change the order in the original list. For example,
     *  if template is [A|B|...], and we want to swap B and A, we can add these
     * three operations in delta:
     *
     *     Remove A (assign null to A's module)
     *     Touch B (just have an entry with B's name that won't change B)
     *     Add A with the original A's values (inserted after B)
     *
     */ var findEntry = function ( result , name , lastOp ) { return result . some ( function ( x , i ) { if ( x . name === name ) { lastOp . index = i ; return true ; } else { return false ; } } ) ; } ; var deleteEntry = function ( result , name , lastOp ) { if ( findEntry ( result , name , lastOp ) ) { result . splice ( lastOp . index , 1 ) ; lastOp . index = lastOp . index - 1 ; } } ; var insertEntry = function ( result , entry , lastOp ) { // splice prepends, and we want after lastOp . index = lastOp . index + 1 ; result . splice ( lastOp . index , 0 , entry ) ; } ; var result = myUtils . deepClone ( template ) ; var lastOp = { index : - 1 } ; delta . forEach ( function ( x ) { if ( x . module === null ) { deleteEntry ( result , x . name , lastOp ) ; } else if ( findEntry ( result , x . name , lastOp ) ) { result [ lastOp . index ] = mergeObj ( result [ lastOp . index ] , x , false ) ; } else { insertEntry ( result , myUtils . deepClone ( x ) , lastOp ) ; } } ) ; return result ; }
Merge two component arrays of matching components.

@param {Array.<specType>} template
@param {Array.<specDeltaType>} delta
@return {Array.<specType>} result
Merge two component arrays of matching components .