const Stack = (function () {
	const top = Symbol('top') //To keep top as private in stack

	class StackNode {
		constructor(data, next = null) {
			this.data = data
			this.next = next
		}
	}

	class Stack {
		constructor() {
			this[top] = null
		}

		push(item) {
			const node = new StackNode(item)
			node.next = this[top]
			this[top] = node
		}

		pop() {
			if (this[top] === null) return null
			const item = this[top].data
			this[top] = this[top].next
			return item
		}

		peek() {
			if (this[top] === null) return null
			return this[top].data
		}

		isEmpty() {
			return this[top] === null
		}

		printStack() {
			const result = []
			let curr = this[top]

			while (curr) {
				result.push(curr.data)
				curr = curr.next
			}
			// console.log(result)
			return result
		}
		stackToString() {
			return JSON.stringify(this.printStack())
		}
	}

	return Stack
})()

module.exports = Stack

Tests (jest):

const { Stack } = require('../src')

test('creates a new instance of Stack', () => {
	const stack = new Stack()
	expect(stack instanceof Stack).toBe(true)
})

describe('peek', () => {
	test('returns top value of stack if it exists', () => {
		const stack = new Stack()
		stack.push(1)
		expect(stack.peek()).toBe(1)
	})

	test('returns null if stack is empty', () => {
		const stack = new Stack()
		stack.push(1)
		expect(stack.peek()).toBe(1)
	})
})

describe('push', () => {
	test('adds item to top of stack', () => {
		const stack = new Stack()
		stack.push(1)
		stack.push(2)
		expect(stack.peek()).toBe(2)
	})
})

describe('pop', () => {
	test('removes and return top item of stack', () => {
		const stack = new Stack()
		stack.push(1)
		stack.push(2)
		expect(stack.pop()).toBe(2)
	})
	test('removes the top item of stack and modifies top to be the next item', () => {
		const stack = new Stack()
		stack.push(1)
		stack.push(2)
		stack.pop()
		expect(stack.peek()).toBe(1)
	})
	test('return null if stack is empty', () => {
		const stack = new Stack()
		expect(stack.pop()).toBe(null)
	})
})

describe('isEmpty', () => {
	test('returns true if stack is empty', () => {
		const stack = new Stack()
		expect(stack.isEmpty()).toBe(true)
	})
})

describe('printStack', () => {
	test('prints all items of stack as an array', () => {
		const stack = new Stack()
		stack.push(1)
		stack.push(2)
		expect(stack.printStack()).toEqual([2, 1])
	})
})