mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	And convert the corresponding function expressions to arrow style
while we’re here.
import * as babelParser from "recast/parsers/babel";
import * as recast from "recast";
import * as tsParser from "recast/parsers/typescript";
import { builders as b, namedTypes as n } from "ast-types";
import K from "ast-types/gen/kinds";
import fs from "fs";
import path from "path";
import process from "process";
const checkExpression = (node: n.Node): node is K.ExpressionKind =>
  n.Expression.check(node);
for (const file of process.argv.slice(2)) {
  console.log("Parsing", file);
  const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), {
    parser: path.extname(file) === ".ts" ? tsParser : babelParser,
  });
  let changed = false;
  recast.visit(ast, {
    visitCallExpression(path) {
      const { callee, arguments: args } = path.node;
      if (
        n.MemberExpression.check(callee) &&
        !callee.computed &&
        n.Identifier.check(callee.object) &&
        callee.object.name === "_" &&
        n.Identifier.check(callee.property) &&
        callee.property.name === "map" &&
        args.length === 2 &&
        checkExpression(args[0]) &&
        checkExpression(args[1])
      ) {
        const [arr, fn] = args;
        path.replace(
          b.callExpression(b.memberExpression(arr, b.identifier("map")), [
            n.FunctionExpression.check(fn) ||
            n.ArrowFunctionExpression.check(fn)
              ? b.arrowFunctionExpression(
                  fn.params,
                  n.BlockStatement.check(fn.body) &&
                    fn.body.body.length === 1 &&
                    n.ReturnStatement.check(fn.body.body[0])
                    ? fn.body.body[0].argument || b.identifier("undefined")
                    : fn.body
                )
              : fn,
          ])
        );
        changed = true;
      }
      this.traverse(path);
    },
  });
  if (changed) {
    console.log("Writing", file);
    fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
  }
}
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
		
	
		
			
				
	
	
		
			331 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			331 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
let is_floating_recipient_bar_showing = false;
 | 
						|
 | 
						|
function top_offset(elem) {
 | 
						|
    return elem.offset().top - $('#tab_bar').safeOuterHeight();
 | 
						|
}
 | 
						|
 | 
						|
exports.first_visible_message = function (bar) {
 | 
						|
    // The first truly visible message would be computed using the
 | 
						|
    // bottom of the floating recipient bar; but we want the date from
 | 
						|
    // the first visible message were the floating recipient bar not
 | 
						|
    // displayed, which will always be the first messages whose bottom
 | 
						|
    // overlaps the floating recipient bar's space (since you ).
 | 
						|
 | 
						|
    const messages = bar.children('.message_row');
 | 
						|
    const frb_bottom = exports.frb_bottom();
 | 
						|
    const frb_top = frb_bottom - 25;
 | 
						|
    let result;
 | 
						|
 | 
						|
    for (let i = 0; i < messages.length; i += 1) {
 | 
						|
        // The details of this comparison function are sensitive, since we're
 | 
						|
        // balancing between three possible bugs:
 | 
						|
        //
 | 
						|
        // * If we compare against the bottom of the floating
 | 
						|
        //   recipient bar, we end up with a bug where if the floating
 | 
						|
        //   recipient bar is just above a normal recipient bar while
 | 
						|
        //   overlapping a series of 1-line messages, there might be 2
 | 
						|
        //   messages occluded by the recipient bar, and we want the
 | 
						|
        //   second one, not the first.
 | 
						|
        //
 | 
						|
        // * If we compare the message bottom against the top of the
 | 
						|
        //   floating recipient bar, and the floating recipient bar is
 | 
						|
        //   over a "Yesterday/Today" message date row, we might
 | 
						|
        //   confusingly have the floating recipient bar display
 | 
						|
        //   e.g. "Yesterday" even though all messages in view were
 | 
						|
        //   actually sent "Today".
 | 
						|
        //
 | 
						|
        // * If the the floating recipient bar is over a
 | 
						|
        //   between-message groups date separator or similar widget,
 | 
						|
        //   there might be no message overlap with the floating
 | 
						|
        //   recipient bar.
 | 
						|
        //
 | 
						|
        // Careful testing of these two corner cases with
 | 
						|
        // message_viewport.scrollTop() to set precise scrolling
 | 
						|
        // positions determines the value for date_bar_height_offset.
 | 
						|
 | 
						|
        let message = $(messages[i]);
 | 
						|
        const message_bottom = top_offset(message) + message.safeOuterHeight();
 | 
						|
        const date_bar_height_offset = 10;
 | 
						|
 | 
						|
        if (message_bottom > frb_top) {
 | 
						|
            result = message;
 | 
						|
        }
 | 
						|
 | 
						|
        // Important: This will break if we ever have things that are
 | 
						|
        // not message rows inside a recipient_row block.
 | 
						|
        message = message.next('.message_row');
 | 
						|
        if (message.length > 0 && result) {
 | 
						|
            // Before returning a result, we check whether the next
 | 
						|
            // message's top is actually below the bottom of the
 | 
						|
            // floating recipient bar; this is different from the
 | 
						|
            // bottom of our current message because there may be a
 | 
						|
            // between-messages date separator row in between.
 | 
						|
            if (top_offset(message) < frb_bottom - date_bar_height_offset) {
 | 
						|
                result = message;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (result) {
 | 
						|
            return result;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // If none of the messages are visible, just take the last message.
 | 
						|
    return $(messages[messages.length - 1]);
 | 
						|
};
 | 
						|
 | 
						|
exports.get_date = function (elem) {
 | 
						|
    const message_row = exports.first_visible_message(elem);
 | 
						|
 | 
						|
    if (!message_row || !message_row.length) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    const msg_id = rows.id(message_row);
 | 
						|
 | 
						|
    if (msg_id === undefined) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    const message = message_store.get(msg_id);
 | 
						|
 | 
						|
    if (!message) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    const time = new XDate(message.timestamp * 1000);
 | 
						|
    const today = new XDate();
 | 
						|
    const rendered_date = timerender.render_date(time, undefined, today)[0].outerHTML;
 | 
						|
 | 
						|
    return rendered_date;
 | 
						|
};
 | 
						|
 | 
						|
exports.frb_bottom = function () {
 | 
						|
    const bar = $("#floating_recipient_bar");
 | 
						|
    const bar_top = top_offset(bar);
 | 
						|
    const bar_bottom = bar_top + bar.safeOuterHeight();
 | 
						|
 | 
						|
    return bar_bottom;
 | 
						|
};
 | 
						|
 | 
						|
exports.relevant_recipient_bars = function () {
 | 
						|
    let elems = [];
 | 
						|
 | 
						|
    // This line of code does a reverse traversal
 | 
						|
    // from the selected message, which should be
 | 
						|
    // in the visible part of the feed, but is sometimes
 | 
						|
    // not exactly where we want.  The value we get
 | 
						|
    // may be be too far up in the feed, but we can
 | 
						|
    // deal with that later.
 | 
						|
    let first_elem = exports.candidate_recipient_bar();
 | 
						|
 | 
						|
    if (!first_elem) {
 | 
						|
        first_elem = $('.focused_table').find('.recipient_row').first();
 | 
						|
    }
 | 
						|
 | 
						|
    if (first_elem.length === 0) {
 | 
						|
        return [];
 | 
						|
    }
 | 
						|
 | 
						|
    elems.push(first_elem);
 | 
						|
 | 
						|
    const max_offset = top_offset($('#compose'));
 | 
						|
    let header_height = first_elem.find('.message_header').safeOuterHeight();
 | 
						|
 | 
						|
    // It's okay to overestimate header_height a bit, as we don't
 | 
						|
    // really need an FRB for a section that barely shows.
 | 
						|
    header_height += 10;
 | 
						|
 | 
						|
    function next(elem) {
 | 
						|
        elem = elem.next();
 | 
						|
        while (elem.length !== 0 && !elem.hasClass("recipient_row")) {
 | 
						|
            elem = elem.next();
 | 
						|
        }
 | 
						|
        return elem;
 | 
						|
    }
 | 
						|
 | 
						|
    // Now start the forward traversal of recipient bars.
 | 
						|
    // We'll stop when we go below the fold.
 | 
						|
    let elem = next(first_elem);
 | 
						|
 | 
						|
    while (elem.length) {
 | 
						|
 | 
						|
        if (top_offset(elem) < header_height) {
 | 
						|
            // If we are close to the top, then the prior
 | 
						|
            // elements we found are no longer relevant,
 | 
						|
            // because either the selected item we started
 | 
						|
            // with in our reverse traversal was too high,
 | 
						|
            // or there's simply not enough room to draw
 | 
						|
            // a recipient bar without it being ugly.
 | 
						|
            elems = [];
 | 
						|
        }
 | 
						|
 | 
						|
        if (top_offset(elem) > max_offset) {
 | 
						|
            // Out of sight, out of mind!
 | 
						|
            // (The element is below the fold, so we stop the
 | 
						|
            // traversal.)
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        elems.push(elem);
 | 
						|
        elem = next(elem);
 | 
						|
    }
 | 
						|
 | 
						|
    if (elems.length === 0) {
 | 
						|
        blueslip.warn('Unexpected situation--maybe viewport height is very short.');
 | 
						|
        return [];
 | 
						|
    }
 | 
						|
 | 
						|
    const items = elems.map((elem, i) => {
 | 
						|
        let date_html;
 | 
						|
        let need_frb;
 | 
						|
 | 
						|
        if (i === 0) {
 | 
						|
            date_html = exports.get_date(elem);
 | 
						|
            need_frb = top_offset(elem) < 0;
 | 
						|
        } else {
 | 
						|
            date_html = elem.find('.recipient_row_date').html();
 | 
						|
            need_frb = false;
 | 
						|
        }
 | 
						|
 | 
						|
        const date_text = $(date_html).text();
 | 
						|
 | 
						|
        // Add title here to facilitate troubleshooting.
 | 
						|
        const title = elem.find('.message_label_clickable').last().attr('title');
 | 
						|
 | 
						|
        const item = {
 | 
						|
            elem: elem,
 | 
						|
            title: title,
 | 
						|
            date_html: date_html,
 | 
						|
            date_text: date_text,
 | 
						|
            need_frb: need_frb,
 | 
						|
        };
 | 
						|
 | 
						|
        return item;
 | 
						|
    });
 | 
						|
 | 
						|
    items[0].show_date = true;
 | 
						|
 | 
						|
    for (let i = 1; i < items.length; i += 1) {
 | 
						|
        items[i].show_date = items[i].date_text !== items[i - 1].date_text;
 | 
						|
    }
 | 
						|
 | 
						|
    for (const item of items) {
 | 
						|
        if (!item.need_frb) {
 | 
						|
            delete item.date_html;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return items;
 | 
						|
};
 | 
						|
 | 
						|
exports.candidate_recipient_bar = function () {
 | 
						|
    // Find a recipient bar that is close to being onscreen
 | 
						|
    // but above the "top".  This function is guaranteed to
 | 
						|
    // return **some** recipient bar that is above the fold,
 | 
						|
    // if there is one, but it may not be the optimal one if
 | 
						|
    // our pointer is messed up.  Starting with the pointer
 | 
						|
    // is just an optimization here, and our caller will do
 | 
						|
    // a forward traversal and clean up as necessary.
 | 
						|
    // In most cases we find the bottom-most of recipient
 | 
						|
    // bars that is still above the fold.
 | 
						|
 | 
						|
    // Start with the pointer's current location.
 | 
						|
    const selected_row = current_msg_list.selected_row();
 | 
						|
 | 
						|
    if (selected_row === undefined || selected_row.length === 0) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    let candidate = rows.get_message_recipient_row(selected_row);
 | 
						|
    if (candidate === undefined) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    while (candidate.length) {
 | 
						|
 | 
						|
        if (candidate.hasClass("recipient_row") && top_offset(candidate) < 0) {
 | 
						|
            return candidate;
 | 
						|
        }
 | 
						|
        // We cannot use .prev(".recipient_row") here, because that
 | 
						|
        // returns nothing if the previous element is not a recipient
 | 
						|
        // row, rather than finding the first recipient_row.
 | 
						|
        candidate = candidate.prev();
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
function show_floating_recipient_bar() {
 | 
						|
    if (!is_floating_recipient_bar_showing) {
 | 
						|
        $("#floating_recipient_bar").css('visibility', 'visible');
 | 
						|
        is_floating_recipient_bar_showing = true;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
let old_source;
 | 
						|
function replace_floating_recipient_bar(source_info) {
 | 
						|
 | 
						|
    const source_recipient_bar = source_info.elem;
 | 
						|
 | 
						|
    let new_label;
 | 
						|
    let other_label;
 | 
						|
    let header;
 | 
						|
 | 
						|
    if (source_recipient_bar !== old_source) {
 | 
						|
        if (source_recipient_bar.children(".message_header_stream").length !== 0) {
 | 
						|
            new_label = $("#current_label_stream");
 | 
						|
            other_label = $("#current_label_private_message");
 | 
						|
            header = source_recipient_bar.children(".message_header_stream");
 | 
						|
        } else {
 | 
						|
            new_label = $("#current_label_private_message");
 | 
						|
            other_label = $("#current_label_stream");
 | 
						|
            header = source_recipient_bar.children(".message_header_private_message");
 | 
						|
        }
 | 
						|
        new_label.find(".message_header").replaceWith(header.clone());
 | 
						|
        other_label.css('display', 'none');
 | 
						|
        new_label.css('display', 'block');
 | 
						|
        new_label.attr("zid", rows.id(rows.first_message_in_group(source_recipient_bar)));
 | 
						|
 | 
						|
        new_label.toggleClass('message-fade', source_recipient_bar.hasClass('message-fade'));
 | 
						|
        old_source = source_recipient_bar;
 | 
						|
    }
 | 
						|
 | 
						|
    const rendered_date = source_info.date_html || '';
 | 
						|
 | 
						|
    $('#floating_recipient_bar').find('.recipient_row_date').html(rendered_date);
 | 
						|
 | 
						|
    show_floating_recipient_bar();
 | 
						|
}
 | 
						|
 | 
						|
exports.hide = function () {
 | 
						|
    if (is_floating_recipient_bar_showing) {
 | 
						|
        $("#floating_recipient_bar").css('visibility', 'hidden');
 | 
						|
        is_floating_recipient_bar_showing = false;
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
exports.de_clutter_dates = function (items) {
 | 
						|
    for (const item of items) {
 | 
						|
        item.elem.find('.recipient_row_date').toggle(item.show_date);
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
exports.update = function () {
 | 
						|
    const items = exports.relevant_recipient_bars();
 | 
						|
 | 
						|
    if (!items || items.length === 0) {
 | 
						|
        exports.hide();
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    exports.de_clutter_dates(items);
 | 
						|
 | 
						|
    if (!items[0].need_frb) {
 | 
						|
        exports.hide();
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    replace_floating_recipient_bar(items[0]);
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
window.floating_recipient_bar = exports;
 |