Source: composer-common/lib/serializer/typedstack.js

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

const Util = require('../util');

/**
 * Tracks a stack of typed instances. The type information is used to detect
 * overflow / underflow bugs by the caller. It also performs basic sanity
 * checking on push/pop to make detecting bugs easier.
 * @private
 * @class
 * @memberof module:composer-common
 */
class TypedStack {

  /**
   * Create the Stack with the resource at the head.
   * @param {Object} resource - the resource to be put at the head of the stack
   */
    constructor(resource) {
        this.stack = [];
        this.push(resource);
    }

    /**
     * Push a new object.
     * @param {Object} obj - the object being visited
     * @param {Object} expectedType - the expected type of the object being pushed
     */
    push(obj, expectedType) {
        if(expectedType && !(obj instanceof expectedType)) {
            throw new Error('Did not find expected type ' + expectedType.constructor.name + ' as argument to push. Found: ' + obj.toString());
        }

        if(Util.isNull(obj)) {
            throw new Error('Pushing null data!');
        }

        this.stack.push(obj);
        //console.log('Push depth is: ' + this.stack.length + ', contents: ' + this.stack.toString() );
    }

    /**
     * Push a new object.
     * @param {Object} expectedType - the type that should be the result of pop
     * @return {Object} the result of pop
     */
    pop(expectedType) {
        this.peek(expectedType);
        return this.stack.pop();
    }

    /**
     * Peek the top of the stack
     * @param {Object} expectedType - the type that should be the result of pop
     * @return {Object} the result of peek
     */
    peek(expectedType) {

        //console.log( 'pop ' );

        if(this.stack.length < 1) {
            throw new Error('Stack is empty!');
        }

        const result = this.stack[this.stack.length-1];
        if(expectedType && !(result instanceof expectedType)) {
            throw new Error('Did not find expected type ' + expectedType + ' on head of stack. Found: ' + result);
        }

        if(Util.isNull(result)) {
            throw new Error('Pop returned invalid data');
        }

        return result;
    }

    /**
     * Clears the stack
     */
    clear() {
        this.stack = [];
    }
}

module.exports = TypedStack;