extractMemberExpressionChain(expression) {
		/** @type {Node} */
		let expr = expression;
		const members = [];
		const membersOptionals = [];
		const memberRanges = [];
		while (expr.type === "MemberExpression") {
			if (expr.computed) {
				if (expr.property.type !== "Literal") break;
				members.push(`${expr.property.value}`); // the literal
				memberRanges.push(/** @type {Range} */ (expr.object.range)); // the range of the expression fragment before the literal
			} else {
				if (expr.property.type !== "Identifier") break;
				members.push(expr.property.name); // the identifier
				memberRanges.push(/** @type {Range} */ (expr.object.range)); // the range of the expression fragment before the identifier
			}
			membersOptionals.push(expr.optional);
			expr = expr.object;
		}

		return {
			members,
			membersOptionals,
			memberRanges,
			object: expr
		};
	}
@param {Expression | Super} expression a member expression
@returns {{ members: string[], object: Expression | Super, membersOptionals: boolean[], memberRanges: Range[] }} member names (reverse order) and remaining object