js/ka-validator.js
/**
     * Recursive method to check if a given node in the AST matches a given
     * node in a Rule tree object. Takes an options object and currently only
     * supports the strict: true|false option. If strict is false, then if a
     * rule node doesn't match a given node in the AST, each possible child of
     * that node in the AST will be tested against the given rule node. This
     * allows more flexible rule structures at the cost of more node comparisons.
     * @param {Object} astNode - An AST Node object to compare
     * @param {Object} ruleNode - A Rule tree object node to check
     * @param {Object} options - The options object to use
     */
Recursive method to check if a given node in the AST matches a given
node in a Rule tree object. Takes an options object and currently only
supports the strict: true|false option. If strict is false, then if a
rule node doesn't match a given node in the AST, each possible child of
that node in the AST will be tested against the given rule node. This
allows more flexible rule structures at the cost of more node comparisons.
@param {Object} astNode - An AST Node object to compare
@param {Object} ruleNode - A Rule tree object node to check
@param {Object} options - The options object to use
Recursive method to check if a given node in the AST matches a given node in a Rule tree object . Takes an options object and currently only supports the strict : true|false option . If strict is false then if a rule node doesn ' t match a given node in the AST each possible child of that node in the AST will be tested against the given rule node . This allows more flexible rule structures at the cost of more node comparisons . @param { Object } astNode - An AST Node object to compare @param { Object } ruleNode - A Rule tree object node to check @param { Object } options - The options object to use
function compareNodeToStructuralRule(astNode, ruleNode, options) {
        var memberName,
            i,
            j,
            found,
            mismatch = false,
            member;
        if (ruleNode.type !== astNode.type && ruleNode.type !== 'Program') {
            mismatch = true;
        } else {
            for (memberName in ruleNode) {
                if (ruleNode.hasOwnProperty(memberName) && memberName !== 'type') {
                    if (Array.isArray(ruleNode[memberName])) {
                        if (!Array.isArray(astNode[memberName])) {
                            mismatch = true;
                            break;
                        }
                        for (i = 0; i < ruleNode[memberName].length; i++) {
                            found = false;
                            for (j = 0; j < astNode[memberName].length; j++) {
                                if (ruleNode[memberName][i].type === astNode[memberName][j].type) {
                                    if (compareNodeToStructuralRule(astNode[memberName][j], ruleNode[memberName][i], options)) {
                                        found = true;
                                        break;
                                    }
                                }
                            }
                            if (!found) {
                                mismatch = true;
                                break;
                            }
                        }
                        if (mismatch) {
                            break;
                        }
                    } else {
                        if (Array.isArray(astNode[memberName])) {
                            mismatch = true;
                            break;
                        }
                        if (!compareNodeToStructuralRule(astNode[memberName], ruleNode[memberName], options)) {
                            mismatch = true;
                            break;
                        }
                    }
                }
            }
        }
        if (mismatch && !options.strict) {
            for (memberName in astNode) {
                if (astNode.hasOwnProperty(memberName)) {
                    member = astNode[memberName];
                    if (member) {
                        if (Array.isArray(member)) {
                            for (i = 0; i < member.length; i++) {
                                if (compareNodeToStructuralRule(member[i], ruleNode, options)) {
                                    return true;
                                }
                            }
                        } else if (member.type) {
                            if (compareNodeToStructuralRule(member, ruleNode, options)) {
                                return true;
                            }
                        }
                    }
                }
            }
        } else {
            return !mismatch;
        }
    }
function compareNodeToStructuralRule ( astNode , ruleNode , options ) { var memberName , i , j , found , mismatch = false , member ; if ( ruleNode . type !== astNode . type && ruleNode . type !== 'Program' ) { mismatch = true ; } else { for ( memberName in ruleNode ) { if ( ruleNode . hasOwnProperty ( memberName ) && memberName !== 'type' ) { if ( Array . isArray ( ruleNode [ memberName ] ) ) { if ( ! Array . isArray ( astNode [ memberName ] ) ) { mismatch = true ; break ; } for ( i = 0 ; i < ruleNode [ memberName ] . length ; i ++ ) { found = false ; for ( j = 0 ; j < astNode [ memberName ] . length ; j ++ ) { if ( ruleNode [ memberName ] [ i ] . type === astNode [ memberName ] [ j ] . type ) { if ( compareNodeToStructuralRule ( astNode [ memberName ] [ j ] , ruleNode [ memberName ] [ i ] , options ) ) { found = true ; break ; } } } if ( ! found ) { mismatch = true ; break ; } } if ( mismatch ) { break ; } } else { if ( Array . isArray ( astNode [ memberName ] ) ) { mismatch = true ; break ; } if ( ! compareNodeToStructuralRule ( astNode [ memberName ] , ruleNode [ memberName ] , options ) ) { mismatch = true ; break ; } } } } } if ( mismatch && ! options . strict ) { for ( memberName in astNode ) { if ( astNode . hasOwnProperty ( memberName ) ) { member = astNode [ memberName ] ; if ( member ) { if ( Array . isArray ( member ) ) { for ( i = 0 ; i < member . length ; i ++ ) { if ( compareNodeToStructuralRule ( member [ i ] , ruleNode , options ) ) { return true ; } } } else if ( member . type ) { if ( compareNodeToStructuralRule ( member , ruleNode , options ) ) { return true ; } } } } } } else { return ! mismatch ; } }
Recursive method to check if a given node in the AST matches a given
 node in a Rule tree object.
Recursive method to check if a given node in the AST matches a given node in a Rule tree object .
//Rule node type doesn't match the AST node type //Consider all the members in the rule node //Exclude type member & prototype members //Member value is array //If ast member value is not array declare mismatch //Iterate over the array in the rule //Find a match for the given type in the AST member values //On a match, descend and check the next level //If none of the member value types matches the member rule type //declare mismatch //If rule member value is not array and ast node member is array //declare a mismatch //Compare child nodes //If strict = false and mismatch occurred, look for all paths down from the current AST //node and re-check the current rule node against those paths