Anders Kaseorg
d7d8632525
pygments_data: Replace JS module with JSON module.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-12 10:09:12 -08:00
Anders Kaseorg
e257253e64
emoji_codes: Replace JS module with JSON module.
...
webpack optimizes JSON modules using JSON.parse("{…}"), which is
faster than the normal JavaScript parser.
Update the backend to use emoji_codes.json too instead of the three
separate JSON files.
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-12 10:09:12 -08:00
Anders Kaseorg
72dddb7af6
zjsunit: Use assert in strict mode.
...
This makes assert.equal and assert.deepEqual compare using === rather
than ==, to catch more bugs.
https://nodejs.org/api/assert.html#assert_strict_mode
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-12 08:16:26 -05:00
Steve Howell
483f1d153d
minor: Remove "spread operator" todo comment.
...
This comment was addressed in
59d55d1e06
2020-02-12 06:10:32 -05:00
Anders Kaseorg
59d55d1e06
js: Use modern spread arguments syntax.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-11 17:43:35 -08:00
Hashir Sarwar
6e14c39468
top_left_corner: Don't export `should_expand_pm_list()`.
...
We don't need to export `should_expand_pm_list` function
since we are not using it anywhere else.
2020-02-11 14:14:59 -08:00
Dinesh
4304d5f8db
auth: Add support for GitLab authentication.
...
With some tweaks by tabbott to the documentation and comments.
Fixes #13694 .
2020-02-11 13:54:17 -08:00
Anders Kaseorg
e66c4ea474
settings_invites: Convert invited_as_values from object to Map.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 15:57:20 -08:00
Anders Kaseorg
ed032817c7
hotspots: Convert HOTSPOT_LOCATIONS from object to Map.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 15:57:20 -08:00
Anders Kaseorg
ee68ef516d
js: Convert _.isString to typeof.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 15:57:20 -08:00
Anders Kaseorg
a3e5fef663
js: Convert _.isObject to typeof.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 15:57:20 -08:00
Anders Kaseorg
9f07cf6b0e
js: Convert _.values to Object.values.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 15:57:20 -08:00
Anders Kaseorg
7ca52f1e80
js: Convert _.keys to Object.keys.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 15:57:20 -08:00
Steve Howell
14396c3e32
presence: Prep for upcoming changes to server data.
...
In the next commit we're going to change what the
server sends for the following:
- page_params
- server responses to /json/users/me/presence
We will **not** yet be changing the format of the data
that we get in events when users update their presence.
It's also just a bit in flux what our final formats
will be for various presence payloads, and different
optimizations may lead us to use different data
structures in different payloads.
So for now we decouple these two things:
raw_info: this is intended to represent a
snapshot of the latest data from the
server, including some data like
timestamps that are only used
in downstream calculations and not
user-facing
exports.presence_info: this is calculated
info for modules like buddy_data that
just need to know active vs. idle and
last_active_date
Another change that happens here is we rename
set_info_for_user to update_info_for_event,
which just makes it clear that the function
expects data in the "event" format (as opposed
to the format for page_params or server
responses).
As of now keeping the intermediate raw_info data
around feels slightly awkward, because we just
immediately calculate presence_info for any kind
of update. This may be sorta surprising if you
just skim the code and see the various timeout
constants. You would think we might be automatically
expiring "active" statuses in the client due to
the simple passage of time, but in fact the precise
places we do this are all triggered by new data
from the server and we re-calculate statuses
immediately.
(There are indirect ways that clients
have timing logic, since they ask the
server for new data at various intervals, but a
smarter client could simply expire users on its
own, or at least with a more efficient transfer
of info between it and the server. One of
the thing that complicates client-side logic
is that server and client clocks may be out
of sync. Also, it's not inherently super expensive
to get updates from the server.)
2020-02-10 14:37:44 -08:00
Steve Howell
75dbc4a2b1
presence: Extract presence.initialize().
2020-02-10 14:37:44 -08:00
Anders Kaseorg
bafdf5229a
js: Convert _.flatten(a, true) to [].concat(...a).
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
62ad436c64
js: Convert _.compact(a) to a.filter(Boolean).
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
d0b0a64af3
js: Convert _.isEmpty(a) to a.length !== 0.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
8abf5da717
js: Convert _.isArray to Array.isArray.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
e1cf5e4630
js: Convert _.reduce to less convoluted code.
...
reduce is almost never a better solution than the alternatives. Avoid
it.
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
612b237cec
js: Convert remaining _.each(a, …) to a.forEach(…).
...
The _.each calls with an inline function expression have already been
converted to for…of loops. We could do that here, but using .forEach
when we’re just reusing an existing function seems like a good
guideline.
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
b566d11d69
js: Convert _.findIndex(a, …) to a.findIndex(…).
...
And convert the corresponding function expressions to arrow style
while we’re here.
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
336a279005
js: Convert _.find(a, …) to a.find(…).
...
And convert the corresponding function expressions to arrow style
while we’re here.
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
cdd774b790
js: Convert _.all(a, …), _.every(a, …) to a.every(…).
...
And convert the corresponding function expressions to arrow style
while we’re here.
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
70ff164f89
js: Convert _.any(a, …), _.some(a, …) to a.some(…).
...
And convert the corresponding function expressions to arrow style
while we’re here.
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
2285ee922e
js: Convert _.contains(a, …) to a.includes(…).
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
ef50346a29
js: Convert _.reject(a, … => …) to a.filter(… => !…).
...
And convert the corresponding function expressions to arrow style
while we’re here.
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
4948240619
js: Convert _.filter(a, …) to a.filter(…).
...
And convert the corresponding function expressions to arrow style
while we’re here.
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
ac7b09d57e
js: Convert _.map(a, …) to a.map(…).
...
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>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
719546641f
js: Convert a.indexOf(…) !== -1 to a.includes(…).
...
Babel polyfills this for us for Internet Explorer.
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, {
visitBinaryExpression(path) {
const { operator, left, right } = path.node;
if (
n.CallExpression.check(left) &&
n.MemberExpression.check(left.callee) &&
!left.callee.computed &&
n.Identifier.check(left.callee.property) &&
left.callee.property.name === "indexOf" &&
left.arguments.length === 1 &&
checkExpression(left.arguments[0]) &&
((["===", "!==", "==", "!=", ">", "<="].includes(operator) &&
n.UnaryExpression.check(right) &&
right.operator == "-" &&
n.Literal.check(right.argument) &&
right.argument.value === 1) ||
([">=", "<"].includes(operator) &&
n.Literal.check(right) &&
right.value === 0))
) {
const test = b.callExpression(
b.memberExpression(left.callee.object, b.identifier("includes")),
[left.arguments[0]]
);
path.replace(
["!==", "!=", ">", ">="].includes(operator)
? test
: b.unaryExpression("!", test)
);
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>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
788c5afbcf
js: Convert _.indexOf(a, …) to a.indexOf(…).
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
29dbf8ec77
schema: Convert _.find used as loop to for…of.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
13b8bf830f
message_viewport: Convert _.every used as loop to for…of.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
4fbee73d1a
emoji_picker: Convert _.any used as loop to for…of.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
2f314a0854
js: Convert _.map on jQuery collections to Array.from.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
7b0dea0351
js: Convert jQuery.each to for…of.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
22f3ec44bc
blueslip: Use modern spread arguments syntax.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
b5bf677717
submessage: Move submessages === undefined check up.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
4fa1075840
popovers: Check for undefined message.edit_history.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
d671d00cbd
settings_profile_fields: Iterate over field_types with Object.values.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Anders Kaseorg
56ab5b4cf4
schema: Iterate over fields with Object.entries.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-10 14:08:12 -08:00
Chris Heald
86faebc2e5
lightbox: Don't blow up for messages not in the message store.
...
This should somewhat reduce the gravity of the failure mode for cases
where the message the user clicked cannot be found (which would be a
significant bug on its own merit in any case).
2020-02-10 14:00:40 -08:00
Chris Heald
c802a1393f
lightbox: Cast zid to an int before looking it up in message_store.
...
The keys for message_store are since the recent Map migration intended
to be integer message IDs, not strings (and likely were always
intended to be integers; the failure mode may simply have shifted).
This may just be a new bug, but this max also fix #9549 ; certainly
we'll want to redo any investigation with this fix in place.
Fixes #9549 .
2020-02-10 13:56:49 -08:00
Steve Howell
fa1059aa2e
stream_data: Remove stream_name param from add_sub().
...
We just get the stream_name from the sub struct now.
This mostly affects node tests.
The only place in real code where we called add_sub()
was when we initialized data from the server.
2020-02-09 22:08:50 -08:00
Vishnu KS
4572be8c27
api: Rename subject_links to topic_links.
...
Fixes #13588
2020-02-07 14:35:22 -08:00
Steve Howell
e9c6653852
node tests: Always enforce blueslip warn/error/fatal.
...
We now require all of our unit tests to handle
blueslip errors for warn/error/fatal. This
simplifies the zblueslip code to not have any
options passed in.
Most of the places changed here fell into two
categories:
- We were just missing a random piece of
setup data in a happy path test.
- We were testing error handling in just
a lazy way to ensure 100% coverage. Often
these error codepaths were fairly
contrived.
The one place where we especially lazy was
the stream_data tests, and those are now
more thorough.
2020-02-07 14:15:44 -08:00
Steve Howell
996d054fe9
messages: Send stream_id for stream messages.
...
This saves a tiny bit of bandwidth, but more
importantly, it protects us against races for
stream name changes. There's some argument that
if the user is thinking they're sending to
old_stream_name, and unbeknownst to them, the
stream has changed to new_stream_name, then we
should fail. But I think 99% of the time the
user just wants the message to go that stream
despite any renames.
In order to verify the blueslip error, we
had to turn on error checking, which required
a tiny fix to a place where we left out
a stream_id for add_sub.
2020-02-07 14:15:44 -08:00
Anders Kaseorg
02511bff1c
js: Automatically convert _.each to for…of.
...
This commit was automatically generated by the following script,
followed by lint --fix and a few small manual lint-related cleanups.
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 { Context } from "ast-types/lib/path-visitor";
import K from "ast-types/gen/kinds";
import { NodePath } from "ast-types/lib/node-path";
import assert from "assert";
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);
const checkStatement = (node: n.Node): node is K.StatementKind =>
n.Statement.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;
let inLoop = false;
let replaceReturn = false;
const visitLoop = (...args: string[]) =>
function(this: Context, path: NodePath) {
for (const arg of args) {
this.visit(path.get(arg));
}
const old = { inLoop };
inLoop = true;
this.visit(path.get("body"));
inLoop = old.inLoop;
return false;
};
recast.visit(ast, {
visitDoWhileStatement: visitLoop("test"),
visitExpressionStatement(path) {
const { expression, comments } = path.node;
let valueOnly;
if (
n.CallExpression.check(expression) &&
n.MemberExpression.check(expression.callee) &&
!expression.callee.computed &&
n.Identifier.check(expression.callee.object) &&
expression.callee.object.name === "_" &&
n.Identifier.check(expression.callee.property) &&
["each", "forEach"].includes(expression.callee.property.name) &&
[2, 3].includes(expression.arguments.length) &&
checkExpression(expression.arguments[0]) &&
(n.FunctionExpression.check(expression.arguments[1]) ||
n.ArrowFunctionExpression.check(expression.arguments[1])) &&
[1, 2].includes(expression.arguments[1].params.length) &&
n.Identifier.check(expression.arguments[1].params[0]) &&
((valueOnly = expression.arguments[1].params[1] === undefined) ||
n.Identifier.check(expression.arguments[1].params[1])) &&
(expression.arguments[2] === undefined ||
n.ThisExpression.check(expression.arguments[2]))
) {
const old = { inLoop, replaceReturn };
inLoop = false;
replaceReturn = true;
this.visit(
path
.get("expression")
.get("arguments")
.get(1)
.get("body")
);
inLoop = old.inLoop;
replaceReturn = old.replaceReturn;
const [right, { body, params }] = expression.arguments;
const loop = b.forOfStatement(
b.variableDeclaration("let", [
b.variableDeclarator(
valueOnly ? params[0] : b.arrayPattern([params[1], params[0]])
),
]),
valueOnly
? right
: b.callExpression(
b.memberExpression(right, b.identifier("entries")),
[]
),
checkStatement(body) ? body : b.expressionStatement(body)
);
loop.comments = comments;
path.replace(loop);
changed = true;
}
this.traverse(path);
},
visitForStatement: visitLoop("init", "test", "update"),
visitForInStatement: visitLoop("left", "right"),
visitForOfStatement: visitLoop("left", "right"),
visitFunction(path) {
this.visit(path.get("params"));
const old = { replaceReturn };
replaceReturn = false;
this.visit(path.get("body"));
replaceReturn = old.replaceReturn;
return false;
},
visitReturnStatement(path) {
if (replaceReturn) {
assert(!inLoop); // could use labeled continue if this ever fires
const { argument, comments } = path.node;
if (argument === null) {
const s = b.continueStatement();
s.comments = comments;
path.replace(s);
} else {
const s = b.expressionStatement(argument);
s.comments = comments;
path.replace(s, b.continueStatement());
}
return false;
}
this.traverse(path);
},
visitWhileStatement: visitLoop("test"),
});
if (changed) {
console.log("Writing", file);
fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
}
}
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-07 14:09:47 -08:00
Anders Kaseorg
b3f63262af
lint: Delegate console.log check to ESLint.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-07 14:09:47 -08:00
Anders Kaseorg
c48eb3d827
extract_people_from_message: Add missing default case.
...
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-07 14:09:47 -08:00