all files / es6/ scopeManager.js

100% Statements 52/52
100% Branches 22/22
100% Functions 8/8
100% Lines 51/51
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101        732× 732× 732×     159× 159×     260× 153×       159×     159× 159× 159× 105×   54× 43× 145× 145×   43×   11×           908× 908× 908× 908× 908× 908× 908×                 907× 907×                   906× 898×     153×         153× 153× 153× 153×       299× 299× 299× 299×      
"use strict";
const Errors = require("./errors");
 
// This class responsibility is to manage the scope
const ScopeManager = class ScopeManager {
	constructor(options) {
		this.scopePath = options.scopePath;
		this.scopeList = options.scopeList;
		this.parser = options.parser;
	}
	loopOver(tag, callback, inverted) {
		inverted = inverted || false;
		return this.loopOverValue(this.getValue(tag), callback, inverted);
	}
	functorIfInverted(inverted, functor, value) {
		if (inverted) {
			functor(value);
		}
	}
	isValueFalsy(value, type) {
		return (value == null || !value || (type === "[object Array]" && value.length === 0));
	}
	loopOverValue(value, functor, inverted) {
		const type = Object.prototype.toString.call(value);
		const currentValue = this.scopeList[this.num];
		if (this.isValueFalsy(value, type)) {
			return this.functorIfInverted(inverted, functor, currentValue);
		}
		if (type === "[object Array]") {
			for (let i = 0, scope; i < value.length; i++) {
				scope = value[i];
				this.functorIfInverted(!inverted, functor, scope);
			}
			return;
		}
		if (type === "[object Object]") {
			return this.functorIfInverted(!inverted, functor, value);
		}
		if (value === true) {
			return this.functorIfInverted(!inverted, functor, currentValue);
		}
	}
	getValue(tag, num) {
		// search in the scopes (in reverse order) and keep the first defined value
		this.num = num == null ? (this.scopeList.length - 1) : num;
		let err;
		let parser;
		let result;
		const scope = this.scopeList[this.num];
		try {
			parser = this.parser(tag);
		}
		catch (error) {
			err = new Errors.XTScopeParserError("Scope parser compilation failed");
			err.properties = {
				id: "scopeparser_compilation_failed",
				tag: tag,
				explanation: `The scope parser for the tag ${tag} failed to compile`,
				rootError: error,
			};
			throw err;
		}
		try {
			result = parser.get(scope, {num: this.num, scopeList: this.scopeList});
		}
		catch (error) {
			err = new Errors.XTScopeParserError("Scope parser execution failed");
			err.properties = {
				id: "scopeparser_execution_failed",
				explanation: `The scope parser for the tag ${tag} failed to execute`,
				scope: scope,
				tag: tag,
				rootError: error,
			};
			throw err;
		}
		if (result == null && this.num > 0) { return this.getValue(tag, this.num - 1); }
		return result;
	}
	createSubScopeManager(scope, tag) {
		const options = {
			scopePath: this.scopePath.slice(0),
			scopeList: this.scopeList.slice(0),
		};
 
		options.parser = this.parser;
		options.scopeList = this.scopeList.concat(scope);
		options.scopePath = this.scopePath.concat(tag);
		return new ScopeManager(options);
	}
};
 
ScopeManager.createBaseScopeManager = function ({parser, tags}) {
	const options = {parser, tags};
	options.scopePath = [];
	options.scopeList = [tags];
	return new ScopeManager(options);
};
 
module.exports = ScopeManager;