Home Manual Reference Source

src/core.js

import assert from 'assert';
import {empty, push, pop} from '@functional-data-structure/persistent-stack';

export const makePath = (current, key) => {
	assert(current !== undefined);
	const itKey = key[Symbol.iterator]();
	for (const part of itKey) {
		const temporary = current.get(part);
		if (temporary === undefined) {
			return makeNonExistingPath(current.set(part), itKey);
		}

		current = temporary;
	}

	return current;
};

export const makeNonExistingPath = (current, key) => {
	assert(current !== undefined);
	for (const part of key) current = current.set(part);
	return current;
};

export const writePath = (root, key, value) => {
	const current = makePath(root, key);
	current.setValue(value);
	return current;
};

export const readPath = (root, key) => {
	const node = getReference(root, key);
	return node === undefined ? undefined : node.value();
};

export const has = (root, key) => getReference(root, key) !== undefined;

export const getReference = (current, key) => {
	assert(current !== undefined);
	for (const part of key) {
		current = current.get(part);
		if (current === undefined) return undefined;
	}

	return current;
};

export const getClosestAncestor = (ancestor, key) => {
	assert(ancestor !== undefined);
	for (const part of key) {
		const current = ancestor.get(part);
		if (current === undefined) return [part, ancestor];
		ancestor = current;
	}

	return [undefined, ancestor];
};

export const erasePath = (current, key) => {
	assert(current !== undefined);
	for (const part of key) {
		current = current.get(part);
		if (current === undefined) return false;
	}

	if (current.value() === undefined) return false;
	current.setValue(undefined);
	return true;
};

export function* enumerate(root) {
	assert(root !== undefined);
	let prefix = empty();
	if (root.value() !== undefined) yield [prefix, root.value()];
	const stack = [root[Symbol.iterator]()];
	while (true) {
		const it = stack.pop();
		const {value, done} = it.next();
		if (done) {
			if (stack.length === 0) break;
			prefix = pop(prefix);
			continue;
		}

		stack.push(it);
		const [k, node] = value;
		prefix = push(prefix, k);
		if (node.value() !== undefined) yield [prefix, node.value()];
		stack.push(node[Symbol.iterator]());
	}
}