| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/"use strict";/** @typedef {import("estree").Node} EsTreeNode *//** @typedef {import("./JavascriptParser").VariableInfoInterface} VariableInfoInterface */const TypeUnknown = 0;const TypeUndefined = 1;const TypeNull = 2;const TypeString = 3;const TypeNumber = 4;const TypeBoolean = 5;const TypeRegExp = 6;const TypeConditional = 7;const TypeArray = 8;const TypeConstArray = 9;const TypeIdentifier = 10;const TypeWrapped = 11;const TypeTemplateString = 12;const TypeBigInt = 13;class BasicEvaluatedExpression {	constructor() {		this.type = TypeUnknown;		/** @type {[number, number]} */		this.range = undefined;		/** @type {boolean} */		this.falsy = false;		/** @type {boolean} */		this.truthy = false;		/** @type {boolean | undefined} */		this.nullish = undefined;		/** @type {boolean} */		this.sideEffects = true;		/** @type {boolean | undefined} */		this.bool = undefined;		/** @type {number | undefined} */		this.number = undefined;		/** @type {bigint | undefined} */		this.bigint = undefined;		/** @type {RegExp | undefined} */		this.regExp = undefined;		/** @type {string | undefined} */		this.string = undefined;		/** @type {BasicEvaluatedExpression[] | undefined} */		this.quasis = undefined;		/** @type {BasicEvaluatedExpression[] | undefined} */		this.parts = undefined;		/** @type {any[] | undefined} */		this.array = undefined;		/** @type {BasicEvaluatedExpression[] | undefined} */		this.items = undefined;		/** @type {BasicEvaluatedExpression[] | undefined} */		this.options = undefined;		/** @type {BasicEvaluatedExpression | undefined} */		this.prefix = undefined;		/** @type {BasicEvaluatedExpression | undefined} */		this.postfix = undefined;		this.wrappedInnerExpressions = undefined;		/** @type {string | VariableInfoInterface | undefined} */		this.identifier = undefined;		/** @type {VariableInfoInterface} */		this.rootInfo = undefined;		/** @type {() => string[]} */		this.getMembers = undefined;		/** @type {() => boolean[]} */		this.getMembersOptionals = undefined;		/** @type {EsTreeNode} */		this.expression = undefined;	}	isUnknown() {		return this.type === TypeUnknown;	}	isNull() {		return this.type === TypeNull;	}	isUndefined() {		return this.type === TypeUndefined;	}	isString() {		return this.type === TypeString;	}	isNumber() {		return this.type === TypeNumber;	}	isBigInt() {		return this.type === TypeBigInt;	}	isBoolean() {		return this.type === TypeBoolean;	}	isRegExp() {		return this.type === TypeRegExp;	}	isConditional() {		return this.type === TypeConditional;	}	isArray() {		return this.type === TypeArray;	}	isConstArray() {		return this.type === TypeConstArray;	}	isIdentifier() {		return this.type === TypeIdentifier;	}	isWrapped() {		return this.type === TypeWrapped;	}	isTemplateString() {		return this.type === TypeTemplateString;	}	/**	 * Is expression a primitive or an object type value?	 * @returns {boolean | undefined} true: primitive type, false: object type, undefined: unknown/runtime-defined	 */	isPrimitiveType() {		switch (this.type) {			case TypeUndefined:			case TypeNull:			case TypeString:			case TypeNumber:			case TypeBoolean:			case TypeBigInt:			case TypeWrapped:			case TypeTemplateString:				return true;			case TypeRegExp:			case TypeArray:			case TypeConstArray:				return false;			default:				return undefined;		}	}	/**	 * Is expression a runtime or compile-time value?	 * @returns {boolean} true: compile time value, false: runtime value	 */	isCompileTimeValue() {		switch (this.type) {			case TypeUndefined:			case TypeNull:			case TypeString:			case TypeNumber:			case TypeBoolean:			case TypeRegExp:			case TypeConstArray:			case TypeBigInt:				return true;			default:				return false;		}	}	/**	 * Gets the compile-time value of the expression	 * @returns {any} the javascript value	 */	asCompileTimeValue() {		switch (this.type) {			case TypeUndefined:				return undefined;			case TypeNull:				return null;			case TypeString:				return this.string;			case TypeNumber:				return this.number;			case TypeBoolean:				return this.bool;			case TypeRegExp:				return this.regExp;			case TypeConstArray:				return this.array;			case TypeBigInt:				return this.bigint;			default:				throw new Error(					"asCompileTimeValue must only be called for compile-time values"				);		}	}	isTruthy() {		return this.truthy;	}	isFalsy() {		return this.falsy;	}	isNullish() {		return this.nullish;	}	/**	 * Can this expression have side effects?	 * @returns {boolean} false: never has side effects	 */	couldHaveSideEffects() {		return this.sideEffects;	}	asBool() {		if (this.truthy) return true;		if (this.falsy || this.nullish) return false;		if (this.isBoolean()) return this.bool;		if (this.isNull()) return false;		if (this.isUndefined()) return false;		if (this.isString()) return this.string !== "";		if (this.isNumber()) return this.number !== 0;		if (this.isBigInt()) return this.bigint !== BigInt(0);		if (this.isRegExp()) return true;		if (this.isArray()) return true;		if (this.isConstArray()) return true;		if (this.isWrapped()) {			return (this.prefix && this.prefix.asBool()) ||				(this.postfix && this.postfix.asBool())				? true				: undefined;		}		if (this.isTemplateString()) {			const str = this.asString();			if (typeof str === "string") return str !== "";		}		return undefined;	}	asNullish() {		const nullish = this.isNullish();		if (nullish === true || this.isNull() || this.isUndefined()) return true;		if (nullish === false) return false;		if (this.isTruthy()) return false;		if (this.isBoolean()) return false;		if (this.isString()) return false;		if (this.isNumber()) return false;		if (this.isBigInt()) return false;		if (this.isRegExp()) return false;		if (this.isArray()) return false;		if (this.isConstArray()) return false;		if (this.isTemplateString()) return false;		if (this.isRegExp()) return false;		return undefined;	}	asString() {		if (this.isBoolean()) return `${this.bool}`;		if (this.isNull()) return "null";		if (this.isUndefined()) return "undefined";		if (this.isString()) return this.string;		if (this.isNumber()) return `${this.number}`;		if (this.isBigInt()) return `${this.bigint}`;		if (this.isRegExp()) return `${this.regExp}`;		if (this.isArray()) {			let array = [];			for (const item of this.items) {				const itemStr = item.asString();				if (itemStr === undefined) return undefined;				array.push(itemStr);			}			return `${array}`;		}		if (this.isConstArray()) return `${this.array}`;		if (this.isTemplateString()) {			let str = "";			for (const part of this.parts) {				const partStr = part.asString();				if (partStr === undefined) return undefined;				str += partStr;			}			return str;		}		return undefined;	}	setString(string) {		this.type = TypeString;		this.string = string;		this.sideEffects = false;		return this;	}	setUndefined() {		this.type = TypeUndefined;		this.sideEffects = false;		return this;	}	setNull() {		this.type = TypeNull;		this.sideEffects = false;		return this;	}	setNumber(number) {		this.type = TypeNumber;		this.number = number;		this.sideEffects = false;		return this;	}	setBigInt(bigint) {		this.type = TypeBigInt;		this.bigint = bigint;		this.sideEffects = false;		return this;	}	setBoolean(bool) {		this.type = TypeBoolean;		this.bool = bool;		this.sideEffects = false;		return this;	}	setRegExp(regExp) {		this.type = TypeRegExp;		this.regExp = regExp;		this.sideEffects = false;		return this;	}	setIdentifier(identifier, rootInfo, getMembers, getMembersOptionals) {		this.type = TypeIdentifier;		this.identifier = identifier;		this.rootInfo = rootInfo;		this.getMembers = getMembers;		this.getMembersOptionals = getMembersOptionals;		this.sideEffects = true;		return this;	}	setWrapped(prefix, postfix, innerExpressions) {		this.type = TypeWrapped;		this.prefix = prefix;		this.postfix = postfix;		this.wrappedInnerExpressions = innerExpressions;		this.sideEffects = true;		return this;	}	setOptions(options) {		this.type = TypeConditional;		this.options = options;		this.sideEffects = true;		return this;	}	addOptions(options) {		if (!this.options) {			this.type = TypeConditional;			this.options = [];			this.sideEffects = true;		}		for (const item of options) {			this.options.push(item);		}		return this;	}	setItems(items) {		this.type = TypeArray;		this.items = items;		this.sideEffects = items.some(i => i.couldHaveSideEffects());		return this;	}	setArray(array) {		this.type = TypeConstArray;		this.array = array;		this.sideEffects = false;		return this;	}	setTemplateString(quasis, parts, kind) {		this.type = TypeTemplateString;		this.quasis = quasis;		this.parts = parts;		this.templateStringKind = kind;		this.sideEffects = parts.some(p => p.sideEffects);		return this;	}	setTruthy() {		this.falsy = false;		this.truthy = true;		this.nullish = false;		return this;	}	setFalsy() {		this.falsy = true;		this.truthy = false;		return this;	}	setNullish(value) {		this.nullish = value;		if (value) return this.setFalsy();		return this;	}	setRange(range) {		this.range = range;		return this;	}	setSideEffects(sideEffects = true) {		this.sideEffects = sideEffects;		return this;	}	setExpression(expression) {		this.expression = expression;		return this;	}}/** * @param {string} flags regexp flags * @returns {boolean} is valid flags */BasicEvaluatedExpression.isValidRegExpFlags = flags => {	const len = flags.length;	if (len === 0) return true;	if (len > 4) return false;	// cspell:word gimy	let remaining = 0b0000; // bit per RegExp flag: gimy	for (let i = 0; i < len; i++)		switch (flags.charCodeAt(i)) {			case 103 /* g */:				if (remaining & 0b1000) return false;				remaining |= 0b1000;				break;			case 105 /* i */:				if (remaining & 0b0100) return false;				remaining |= 0b0100;				break;			case 109 /* m */:				if (remaining & 0b0010) return false;				remaining |= 0b0010;				break;			case 121 /* y */:				if (remaining & 0b0001) return false;				remaining |= 0b0001;				break;			default:				return false;		}	return true;};module.exports = BasicEvaluatedExpression;
 |