eslint: Fix no-useless-concat.

https://eslint.org/docs/rules/no-useless-concat

And add some escaping to static/js/markdown.js while I’m here.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2020-10-07 04:17:55 -07:00 committed by Tim Abbott
parent 043c34d944
commit 81d21068b5
13 changed files with 41 additions and 95 deletions

View File

@ -85,6 +85,7 @@
} }
], ],
"no-use-before-define": ["error", {"functions": false}], "no-use-before-define": ["error", {"functions": false}],
"no-useless-concat": "error",
"no-useless-constructor": "error", "no-useless-constructor": "error",
"no-var": "error", "no-var": "error",
"object-shorthand": "error", "object-shorthand": "error",

View File

@ -690,7 +690,7 @@ run_test("send_message", () => {
// Setting message content with a host server link and we will assert // Setting message content with a host server link and we will assert
// later that this has been converted to a relative link. // later that this has been converted to a relative link.
$("#compose-textarea").val("[foobar]" + "(https://foo.com/user_uploads/123456)"); $("#compose-textarea").val("[foobar](https://foo.com/user_uploads/123456)");
$("#compose-textarea").trigger("blur"); $("#compose-textarea").trigger("blur");
$("#compose-send-status").show(); $("#compose-send-status").show();
$("#compose-send-button").prop("disabled", true); $("#compose-send-button").prop("disabled", true);

View File

@ -223,7 +223,7 @@ run_test("filtering", () => {
const new_data = ["greta", "faye", "gary", "frank", "giraffe", "fox"]; const new_data = ["greta", "faye", "gary", "frank", "giraffe", "fox"];
widget.replace_list_data(new_data); widget.replace_list_data(new_data);
expected_html = "<div>greta</div>" + "<div>gary</div>" + "<div>giraffe</div>"; expected_html = "<div>greta</div><div>gary</div><div>giraffe</div>";
assert.deepEqual(container.appended_data.html(), expected_html); assert.deepEqual(container.appended_data.html(), expected_html);
}); });
@ -240,7 +240,7 @@ run_test("no filtering", () => {
const widget = list_render.create(container, ["apple", "banana"], opts); const widget = list_render.create(container, ["apple", "banana"], opts);
widget.render(); widget.render();
const expected_html = "<div>apple</div>" + "<div>banana</div>"; const expected_html = "<div>apple</div><div>banana</div>";
assert.deepEqual(container.appended_data.html(), expected_html); assert.deepEqual(container.appended_data.html(), expected_html);
}); });

View File

@ -364,12 +364,12 @@ run_test("marked", () => {
{ {
input: "This is a #**Denmark>some topic** stream_topic link", input: "This is a #**Denmark>some topic** stream_topic link",
expected: expected:
'<p>This is a <a class="stream-topic" data-stream-id="1" href="/#narrow/stream/1-Denmark/topic/some.20topic">#Denmark > some topic</a> stream_topic link</p>', '<p>This is a <a class="stream-topic" data-stream-id="1" href="/#narrow/stream/1-Denmark/topic/some.20topic">#Denmark &gt; some topic</a> stream_topic link</p>',
}, },
{ {
input: "This has two links: #**Denmark>some topic** and #**social>other topic**.", input: "This has two links: #**Denmark>some topic** and #**social>other topic**.",
expected: expected:
'<p>This has two links: <a class="stream-topic" data-stream-id="1" href="/#narrow/stream/1-Denmark/topic/some.20topic">#Denmark > some topic</a> and <a class="stream-topic" data-stream-id="2" href="/#narrow/stream/2-social/topic/other.20topic">#social > other topic</a>.</p>', '<p>This has two links: <a class="stream-topic" data-stream-id="1" href="/#narrow/stream/1-Denmark/topic/some.20topic">#Denmark &gt; some topic</a> and <a class="stream-topic" data-stream-id="2" href="/#narrow/stream/2-social/topic/other.20topic">#social &gt; other topic</a>.</p>',
}, },
{ {
input: "This is not a #**Denmark>** stream_topic link", input: "This is not a #**Denmark>** stream_topic link",
@ -512,7 +512,7 @@ run_test("marked", () => {
{ {
input: "#**Bobby <h1>Tables</h1>**", input: "#**Bobby <h1>Tables</h1>**",
expected: expected:
'<p><a class="stream-topic" data-stream-id="4" href="/#narrow/stream/4-Bobby-.3Ch1/topic/Tables.3C.2Fh1.3E">#Bobby &lt;h1 > Tables&lt;/h1&gt;</a></p>', '<p><a class="stream-topic" data-stream-id="4" href="/#narrow/stream/4-Bobby-.3Ch1/topic/Tables.3C.2Fh1.3E">#Bobby &lt;h1 &gt; Tables&lt;/h1&gt;</a></p>',
}, },
{ {
input: "#**& &amp; &amp;amp;**", input: "#**& &amp; &amp;amp;**",
@ -522,7 +522,7 @@ run_test("marked", () => {
{ {
input: "#**& &amp; &amp;amp;>& &amp; &amp;amp;**", input: "#**& &amp; &amp;amp;>& &amp; &amp;amp;**",
expected: expected:
'<p><a class="stream-topic" data-stream-id="5" href="/#narrow/stream/5-.26-.26.20.26amp.3B/topic/.26.20.26.20.26amp.3B">#&amp; &amp; &amp;amp; > &amp; &amp; &amp;amp;</a></p>', '<p><a class="stream-topic" data-stream-id="5" href="/#narrow/stream/5-.26-.26.20.26amp.3B/topic/.26.20.26.20.26amp.3B">#&amp; &amp; &amp;amp; &gt; &amp; &amp; &amp;amp;</a></p>',
}, },
]; ];

View File

@ -885,7 +885,7 @@ run_test("updates", () => {
// old email. // old email.
blueslip.expect( blueslip.expect(
"warn", "warn",
"Obsolete email passed to get_by_email: " + "FOO@example.com new email = bar@example.com", "Obsolete email passed to get_by_email: FOO@example.com new email = bar@example.com",
); );
person = people.get_by_email(old_email); person = people.get_by_email(old_email);
assert.equal(person.user_id, user_id); assert.equal(person.user_id, user_id);

View File

@ -15,10 +15,7 @@ run_test("basics", () => {
const html = vdom.render_tag(ul); const html = vdom.render_tag(ul);
assert.equal( assert.equal(html, '<ul class="foo" title="cats &amp; &lt;&quot;dogs&quot;&gt;">\n\n</ul>');
html,
'<ul class="foo" title="cats &amp; &lt;&quot;dogs&quot;&gt;">\n\n' + "</ul>",
);
}); });
run_test("attribute escaping", () => { run_test("attribute escaping", () => {
@ -59,7 +56,7 @@ run_test("attribute updates", () => {
const html = vdom.render_tag(ul); const html = vdom.render_tag(ul);
assert.equal(html, '<ul class="same" color="blue" id="101">\n\n' + "</ul>"); assert.equal(html, '<ul class="same" color="blue" id="101">\n\n</ul>');
let updated; let updated;
let removed; let removed;
@ -135,10 +132,7 @@ run_test("children", () => {
vdom.update(replace_content, find, ul); vdom.update(replace_content, find, ul);
assert.equal( assert.equal(rendered_html, "<ul>\n<li>foo1</li>\n<li>foo2</li>\n<li>foo3</li>\n</ul>");
rendered_html,
"<ul>\n" + "<li>foo1</li>\n" + "<li>foo2</li>\n" + "<li>foo3</li>\n" + "</ul>",
);
// Force a complete redraw. // Force a complete redraw.
const new_nodes = make_children([4, 5]); const new_nodes = make_children([4, 5]);
@ -150,10 +144,7 @@ run_test("children", () => {
const new_ul = vdom.ul(new_opts); const new_ul = vdom.ul(new_opts);
vdom.update(replace_content, find, new_ul, ul); vdom.update(replace_content, find, new_ul, ul);
assert.equal( assert.equal(rendered_html, '<ul class="main">\n<li>foo4</li>\n<li>foo5</li>\n</ul>');
rendered_html,
'<ul class="main">\n' + "<li>foo4</li>\n" + "<li>foo5</li>\n" + "</ul>",
);
}); });
run_test("partial updates", () => { run_test("partial updates", () => {
@ -176,10 +167,7 @@ run_test("partial updates", () => {
vdom.update(replace_content, find, ul); vdom.update(replace_content, find, ul);
assert.equal( assert.equal(rendered_html, "<ul>\n<li>foo1</li>\n<li>foo2</li>\n<li>foo3</li>\n</ul>");
rendered_html,
"<ul>\n" + "<li>foo1</li>\n" + "<li>foo2</li>\n" + "<li>foo3</li>\n" + "</ul>",
);
replace_content = () => { replace_content = () => {
throw new Error("should not replace entire html"); throw new Error("should not replace entire html");

View File

@ -37,10 +37,7 @@ exports.process_message = function (message) {
const before_punctuation = "\\s|^|>|[\\(\\\".,';\\[]"; const before_punctuation = "\\s|^|>|[\\(\\\".,';\\[]";
const after_punctuation = "\\s|$|<|[\\)\\\"\\?!:.,';\\]!]"; const after_punctuation = "\\s|$|<|[\\)\\\"\\?!:.,';\\]!]";
const regex = new RegExp( const regex = new RegExp(`(${before_punctuation})(${clean})(${after_punctuation})`, "ig");
"(" + before_punctuation + ")" + "(" + clean + ")" + "(" + after_punctuation + ")",
"ig",
);
message.content = message.content.replace( message.content = message.content.replace(
regex, regex,
(match, before, word, after, offset, content) => { (match, before, word, after, offset, content) => {

View File

@ -155,7 +155,7 @@ function report_error(msg, stack, opts) {
error() { error() {
if (opts.show_ui_msg && ui_report !== undefined) { if (opts.show_ui_msg && ui_report !== undefined) {
ui_report.message( ui_report.message(
"Oops. It seems something has gone wrong. " + "Please try reloading the page.", "Oops. It seems something has gone wrong. Please try reloading the page.",
$("#home-error"), $("#home-error"),
"alert-error", "alert-error",
); );

View File

@ -166,7 +166,7 @@ exports.by_conversation_and_time_uri = function (message) {
}; };
exports.stream_edit_uri = function (sub) { exports.stream_edit_uri = function (sub) {
const hash = "#streams" + "/" + sub.stream_id + "/" + exports.encodeHashComponent(sub.name); const hash = `#streams/${sub.stream_id}/${exports.encodeHashComponent(sub.name)}`;
return hash; return hash;
}; };

View File

@ -102,7 +102,7 @@ exports.apply_markdown = function (message) {
userMentionHandler(mention, silently) { userMentionHandler(mention, silently) {
if (mention === "all" || mention === "everyone" || mention === "stream") { if (mention === "all" || mention === "everyone" || mention === "stream") {
message.mentioned = true; message.mentioned = true;
return '<span class="user-mention" data-user-id="*">' + "@" + mention + "</span>"; return `<span class="user-mention" data-user-id="*">@${_.escape(mention)}</span>`;
} }
let full_name; let full_name;
@ -160,15 +160,15 @@ exports.apply_markdown = function (message) {
} }
let str = ""; let str = "";
if (silently) { if (silently) {
str += '<span class="user-mention silent" data-user-id="' + user_id + '">'; str += `<span class="user-mention silent" data-user-id="${_.escape(user_id)}">`;
} else { } else {
str += '<span class="user-mention" data-user-id="' + user_id + '">@'; str += `<span class="user-mention" data-user-id="${_.escape(user_id)}">@`;
} }
// If I mention "@aLiCe sMITH", I still want "Alice Smith" to // If I mention "@aLiCe sMITH", I still want "Alice Smith" to
// show in the pill. // show in the pill.
const actual_full_name = helpers.get_actual_name_from_user_id(user_id); const actual_full_name = helpers.get_actual_name_from_user_id(user_id);
return str + _.escape(actual_full_name) + "</span>"; return `${str}${_.escape(actual_full_name)}</span>`;
}, },
groupMentionHandler(name) { groupMentionHandler(name) {
const group = helpers.get_user_group_from_name(name); const group = helpers.get_user_group_from_name(name);
@ -176,14 +176,9 @@ exports.apply_markdown = function (message) {
if (helpers.is_member_of_user_group(group.id, helpers.my_user_id())) { if (helpers.is_member_of_user_group(group.id, helpers.my_user_id())) {
message.mentioned = true; message.mentioned = true;
} }
return ( return `<span class="user-group-mention" data-user-group-id="${_.escape(
'<span class="user-group-mention" data-user-group-id="' + group.id,
group.id + )}">@${_.escape(group.name)}</span>`;
'">' +
"@" +
_.escape(group.name) +
"</span>"
);
} }
return undefined; return undefined;
}, },
@ -251,19 +246,9 @@ exports.is_status_message = function (raw_content) {
}; };
function make_emoji_span(codepoint, title, alt_text) { function make_emoji_span(codepoint, title, alt_text) {
return ( return `<span aria-label="${_.escape(title)}" class="emoji emoji-${_.escape(
'<span aria-label="' + codepoint,
title + )}" role="img" title="${_.escape(title)}">${_.escape(alt_text)}</span>`;
'"' +
' class="emoji emoji-' +
codepoint +
'"' +
' role="img" title="' +
title +
'">' +
alt_text +
"</span>"
);
} }
function handleUnicodeEmoji(unicode_emoji) { function handleUnicodeEmoji(unicode_emoji) {
@ -293,17 +278,9 @@ function handleEmoji(emoji_name) {
const emoji_url = emoji.get_realm_emoji_url(emoji_name); const emoji_url = emoji.get_realm_emoji_url(emoji_name);
if (emoji_url) { if (emoji_url) {
return ( return `<img alt="${_.escape(alt_text)}" class="emoji" src="${_.escape(
'<img alt="' + emoji_url,
alt_text + )}" title="${_.escape(title)}">`;
'"' +
' class="emoji" src="' +
emoji_url +
'"' +
' title="' +
title +
'">'
);
} }
const codepoint = emoji.get_emoji_codepoint(emoji_name); const codepoint = emoji.get_emoji_codepoint(emoji_name);
@ -350,18 +327,9 @@ function handleStream(stream_name) {
return undefined; return undefined;
} }
const href = helpers.stream_hash(stream.stream_id); const href = helpers.stream_hash(stream.stream_id);
return ( return `<a class="stream" data-stream-id="${_.escape(stream.stream_id)}" href="/${_.escape(
'<a class="stream" data-stream-id="' + href,
stream.stream_id + )}">#${_.escape(stream.name)}</a>`;
'" ' +
'href="/' +
href +
'"' +
">" +
"#" +
_.escape(stream.name) +
"</a>"
);
} }
function handleStreamTopic(stream_name, topic) { function handleStreamTopic(stream_name, topic) {
@ -370,18 +338,10 @@ function handleStreamTopic(stream_name, topic) {
return undefined; return undefined;
} }
const href = helpers.stream_topic_hash(stream.stream_id, topic); const href = helpers.stream_topic_hash(stream.stream_id, topic);
const text = "#" + _.escape(stream.name) + " > " + _.escape(topic); const text = `#${stream.name} > ${topic}`;
return ( return `<a class="stream-topic" data-stream-id="${_.escape(
'<a class="stream-topic" data-stream-id="' + stream.stream_id,
stream.stream_id + )}" href="/${_.escape(href)}">${_.escape(text)}</a>`;
'" ' +
'href="/' +
href +
'"' +
">" +
text +
"</a>"
);
} }
function handleRealmFilter(pattern, matches) { function handleRealmFilter(pattern, matches) {
@ -404,7 +364,7 @@ function handleTex(tex, fullmatch) {
} catch (error) { } catch (error) {
if (error.message.startsWith("KaTeX parse error")) { if (error.message.startsWith("KaTeX parse error")) {
// TeX syntax error // TeX syntax error
return '<span class="tex-error">' + _.escape(fullmatch) + "</span>"; return `<span class="tex-error">${_.escape(fullmatch)}</span>`;
} }
blueslip.error(error); blueslip.error(error);
return undefined; return undefined;

View File

@ -188,7 +188,7 @@ function handle_unsuccessful_response(response) {
try { try {
const status_code = response.statusCode().status; const status_code = response.statusCode().status;
response = JSON.parse(response.responseText); response = JSON.parse(response.responseText);
set_results_notice("Result: " + "(" + status_code + ") " + response.msg, "warning"); set_results_notice(`Result: (${status_code}) ${response.msg}`, "warning");
} catch { } catch {
// If the response is not a JSON response, then it is probably // If the response is not a JSON response, then it is probably
// Django returning an HTML response containing a stack trace // Django returning an HTML response containing a stack trace

View File

@ -73,7 +73,7 @@ class MessageState {
} }
blueslip.log( blueslip.log(
"Restarting get_events due to " + "delayed receipt of sent message " + this.local_id, `Restarting get_events due to delayed receipt of sent message ${this.local_id}`,
); );
server_events.restart_get_events(); server_events.restart_get_events();

View File

@ -81,7 +81,7 @@ function make_stream_default(stream_id) {
exports.delete_default_stream = function (stream_id, default_stream_row, alert_element) { exports.delete_default_stream = function (stream_id, default_stream_row, alert_element) {
channel.del({ channel.del({
url: "/json/default_streams" + "?" + $.param({stream_id}), url: "/json/default_streams?" + $.param({stream_id}),
error(xhr) { error(xhr) {
ui_report.generic_row_button_error(xhr, alert_element); ui_report.generic_row_button_error(xhr, alert_element);
}, },