function validateNode(node) {
        var oldValue = node.valid;
        var oldChanged = node.changed;
        node.valid = true;
        var subflow;
        var isValid;
        var hasChanged;
        if (node.type.indexOf("subflow:")===0) {
            subflow = RED.nodes.subflow(node.type.substring(8));
            isValid = subflow.valid;
            hasChanged = subflow.changed;
            if (isValid === undefined) {
                isValid = validateNode(subflow);
                hasChanged = subflow.changed;
            }
            node.valid = isValid && validateNodeProperties(node, node._def.defaults, node);
            node.changed = node.changed || hasChanged;
        } else if (node._def) {
            node.valid = validateNodeProperties(node, node._def.defaults, node);
            if (node._def._creds) {
                node.valid = node.valid && validateNodeProperties(node, node._def.credentials, node._def._creds);
            }
        } else if (node.type == "subflow") {
            var subflowNodes = RED.nodes.filterNodes({z:node.id});
            for (var i=0;i<subflowNodes.length;i++) {
                isValid = subflowNodes[i].valid;
                hasChanged = subflowNodes[i].changed;
                if (isValid === undefined) {
                    isValid = validateNode(subflowNodes[i]);
                    hasChanged = subflowNodes[i].changed;
                }
                node.valid = node.valid && isValid;
                node.changed = node.changed || hasChanged;
            }
            var subflowInstances = RED.nodes.filterNodes({type:"subflow:"+node.id});
            var modifiedTabs = {};
            for (i=0;i<subflowInstances.length;i++) {
                subflowInstances[i].valid = node.valid;
                subflowInstances[i].changed = subflowInstances[i].changed || node.changed;
                subflowInstances[i].dirty = true;
                modifiedTabs[subflowInstances[i].z] = true;
            }
            Object.keys(modifiedTabs).forEach(function(id) {
                var subflow = RED.nodes.subflow(id);
                if (subflow) {
                    validateNode(subflow);
                }
            });
        }
        if (oldValue !== node.valid || oldChanged !== node.changed) {
            node.dirty = true;
            subflow = RED.nodes.subflow(node.z);
            if (subflow) {
                validateNode(subflow);
            }
        }
        return node.valid;
    }
/**
     * Validate a node
     * @param node - the node being validated
     * @returns {boolean} whether the node is valid. Sets node.dirty if needed
     */
Validate a node
@param node - the node being validated
@returns {boolean} whether the node is valid.
Validate a node @param node - the node being validated @returns { boolean } whether the node is valid .
function validateNode(node) {
        var oldValue = node.valid;
        var oldChanged = node.changed;
        node.valid = true;
        var subflow;
        var isValid;
        var hasChanged;
        if (node.type.indexOf("subflow:")===0) {
            subflow = RED.nodes.subflow(node.type.substring(8));
            isValid = subflow.valid;
            hasChanged = subflow.changed;
            if (isValid === undefined) {
                isValid = validateNode(subflow);
                hasChanged = subflow.changed;
            }
            node.valid = isValid && validateNodeProperties(node, node._def.defaults, node);
            node.changed = node.changed || hasChanged;
        } else if (node._def) {
            node.valid = validateNodeProperties(node, node._def.defaults, node);
            if (node._def._creds) {
                node.valid = node.valid && validateNodeProperties(node, node._def.credentials, node._def._creds);
            }
        } else if (node.type == "subflow") {
            var subflowNodes = RED.nodes.filterNodes({z:node.id});
            for (var i=0;i<subflowNodes.length;i++) {
                isValid = subflowNodes[i].valid;
                hasChanged = subflowNodes[i].changed;
                if (isValid === undefined) {
                    isValid = validateNode(subflowNodes[i]);
                    hasChanged = subflowNodes[i].changed;
                }
                node.valid = node.valid && isValid;
                node.changed = node.changed || hasChanged;
            }
            var subflowInstances = RED.nodes.filterNodes({type:"subflow:"+node.id});
            var modifiedTabs = {};
            for (i=0;i<subflowInstances.length;i++) {
                subflowInstances[i].valid = node.valid;
                subflowInstances[i].changed = subflowInstances[i].changed || node.changed;
                subflowInstances[i].dirty = true;
                modifiedTabs[subflowInstances[i].z] = true;
            }
            Object.keys(modifiedTabs).forEach(function(id) {
                var subflow = RED.nodes.subflow(id);
                if (subflow) {
                    validateNode(subflow);
                }
            });
        }
        if (oldValue !== node.valid || oldChanged !== node.changed) {
            node.dirty = true;
            subflow = RED.nodes.subflow(node.z);
            if (subflow) {
                validateNode(subflow);
            }
        }
        return node.valid;
    }
function validateNode ( node ) { var oldValue = node . valid ; var oldChanged = node . changed ; node . valid = true ; var subflow ; var isValid ; var hasChanged ; if ( node . type . indexOf ( "subflow:" ) === 0 ) { subflow = RED . nodes . subflow ( node . type . substring ( 8 ) ) ; isValid = subflow . valid ; hasChanged = subflow . changed ; if ( isValid === undefined ) { isValid = validateNode ( subflow ) ; hasChanged = subflow . changed ; } node . valid = isValid && validateNodeProperties ( node , node . _def . defaults , node ) ; node . changed = node . changed || hasChanged ; } else if ( node . _def ) { node . valid = validateNodeProperties ( node , node . _def . defaults , node ) ; if ( node . _def . _creds ) { node . valid = node . valid && validateNodeProperties ( node , node . _def . credentials , node . _def . _creds ) ; } } else if ( node . type == "subflow" ) { var subflowNodes = RED . nodes . filterNodes ( { z : node . id } ) ; for ( var i = 0 ; i < subflowNodes . length ; i ++ ) { isValid = subflowNodes [ i ] . valid ; hasChanged = subflowNodes [ i ] . changed ; if ( isValid === undefined ) { isValid = validateNode ( subflowNodes [ i ] ) ; hasChanged = subflowNodes [ i ] . changed ; } node . valid = node . valid && isValid ; node . changed = node . changed || hasChanged ; } var subflowInstances = RED . nodes . filterNodes ( { type : "subflow:" + node . id } ) ; var modifiedTabs = { } ; for ( i = 0 ; i < subflowInstances . length ; i ++ ) { subflowInstances [ i ] . valid = node . valid ; subflowInstances [ i ] . changed = subflowInstances [ i ] . changed || node . changed ; subflowInstances [ i ] . dirty = true ; modifiedTabs [ subflowInstances [ i ] . z ] = true ; } Object . keys ( modifiedTabs ) . forEach ( function ( id ) { var subflow = RED . nodes . subflow ( id ) ; if ( subflow ) { validateNode ( subflow ) ; } } ) ; } if ( oldValue !== node . valid || oldChanged !== node . changed ) { node . dirty = true ; subflow = RED . nodes . subflow ( node . z ) ; if ( subflow ) { validateNode ( subflow ) ; } } return node . valid ; }
Validate a node
 @param node - the node being validated
 @returns {boolean} whether the node is valid.
Validate a node @param node - the node being validated @returns { boolean } whether the node is valid .