2018-07-14 12:46:02 +02:00
|
|
|
set_global('page_params', {
|
|
|
|
search_pills_enabled: false,
|
|
|
|
});
|
2020-01-02 15:17:10 +01:00
|
|
|
set_global('message_store', {
|
|
|
|
user_ids: () => [],
|
|
|
|
});
|
|
|
|
|
2020-02-25 12:46:14 +01:00
|
|
|
const settings_config = zrequire('settings_config');
|
|
|
|
page_params.realm_email_address_visibility =
|
|
|
|
settings_config.email_address_visibility_values.admins_only.code;
|
|
|
|
|
2018-07-14 12:46:02 +02:00
|
|
|
zrequire('typeahead_helper');
|
2019-07-12 02:03:55 +02:00
|
|
|
set_global('Handlebars', global.make_handlebars());
|
2018-07-14 12:46:02 +02:00
|
|
|
zrequire('Filter', 'js/filter');
|
|
|
|
zrequire('narrow_state');
|
|
|
|
zrequire('stream_data');
|
2020-03-22 18:40:05 +01:00
|
|
|
zrequire('stream_topic_history');
|
2018-07-14 12:46:02 +02:00
|
|
|
zrequire('people');
|
|
|
|
zrequire('unread');
|
|
|
|
zrequire('common');
|
2019-11-02 00:06:25 +01:00
|
|
|
const search = zrequire('search_suggestion');
|
2018-07-14 12:46:02 +02:00
|
|
|
|
2019-12-25 16:58:11 +01:00
|
|
|
search.max_num_of_search_results = 15;
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const bob = {
|
2018-07-14 12:46:02 +02:00
|
|
|
email: 'bob@zulip.com',
|
|
|
|
full_name: 'Bob Roberts',
|
|
|
|
user_id: 42,
|
|
|
|
};
|
|
|
|
|
|
|
|
function init() {
|
|
|
|
people.init();
|
|
|
|
people.add(bob);
|
|
|
|
people.initialize_current_user(bob.user_id);
|
|
|
|
}
|
|
|
|
init();
|
|
|
|
|
|
|
|
set_global('narrow', {});
|
2020-02-25 12:46:14 +01:00
|
|
|
|
|
|
|
page_params.is_admin = true;
|
2018-07-14 12:46:02 +02:00
|
|
|
|
2020-03-22 18:40:05 +01:00
|
|
|
stream_topic_history.reset();
|
2018-07-14 12:46:02 +02:00
|
|
|
|
|
|
|
run_test('basic_get_suggestions', () => {
|
2019-11-02 00:06:25 +01:00
|
|
|
const query = 'fred';
|
2018-07-14 12:46:02 +02:00
|
|
|
|
|
|
|
global.stream_data.subscribed_streams = function () {
|
|
|
|
return [];
|
|
|
|
};
|
|
|
|
|
|
|
|
global.narrow_state.stream = function () {
|
|
|
|
return 'office';
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const expected = [
|
2018-07-14 12:46:02 +02:00
|
|
|
'fred',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
});
|
|
|
|
|
|
|
|
run_test('subset_suggestions', () => {
|
2019-11-02 00:06:25 +01:00
|
|
|
const query = 'stream:Denmark topic:Hamlet shakespeare';
|
2018-07-14 12:46:02 +02:00
|
|
|
|
|
|
|
global.stream_data.subscribed_streams = function () {
|
|
|
|
return [];
|
|
|
|
};
|
|
|
|
|
|
|
|
global.narrow_state.stream = function () {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const expected = [
|
2018-07-14 12:46:02 +02:00
|
|
|
"stream:Denmark topic:Hamlet shakespeare",
|
|
|
|
"stream:Denmark topic:Hamlet",
|
|
|
|
"stream:Denmark",
|
|
|
|
];
|
|
|
|
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
});
|
|
|
|
|
|
|
|
run_test('private_suggestions', () => {
|
|
|
|
global.stream_data.subscribed_streams = function () {
|
|
|
|
return [];
|
|
|
|
};
|
|
|
|
|
|
|
|
global.narrow_state.stream = function () {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const ted =
|
2018-07-14 12:46:02 +02:00
|
|
|
{
|
|
|
|
email: 'ted@zulip.com',
|
|
|
|
user_id: 101,
|
|
|
|
full_name: 'Ted Smith',
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const alice =
|
2018-07-14 12:46:02 +02:00
|
|
|
{
|
|
|
|
email: 'alice@zulip.com',
|
|
|
|
user_id: 102,
|
|
|
|
full_name: 'Alice Ignore',
|
|
|
|
};
|
|
|
|
|
|
|
|
people.add(ted);
|
|
|
|
people.add(alice);
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
let query = 'is:private';
|
|
|
|
let suggestions = search.get_suggestions_legacy(query);
|
|
|
|
let expected = [
|
2018-07-14 12:46:02 +02:00
|
|
|
"is:private",
|
|
|
|
"pm-with:alice@zulip.com",
|
|
|
|
"pm-with:bob@zulip.com",
|
|
|
|
"pm-with:ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'is:private al';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"is:private al",
|
|
|
|
"is:private is:alerted",
|
|
|
|
"is:private sender:alice@zulip.com",
|
|
|
|
"is:private pm-with:alice@zulip.com",
|
|
|
|
"is:private group-pm-with:alice@zulip.com",
|
|
|
|
"is:private",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'pm-with:t';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"pm-with:t",
|
|
|
|
"pm-with:ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = '-pm-with:t';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"-pm-with:t",
|
|
|
|
"is:private -pm-with:ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'pm-with:ted@zulip.com';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"pm-with:ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'sender:ted';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"sender:ted",
|
|
|
|
"sender:ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'sender:te';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"sender:te",
|
|
|
|
"sender:ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = '-sender:te';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"-sender:te",
|
|
|
|
"-sender:ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'sender:ted@zulip.com';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"sender:ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'is:unread from:ted';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"is:unread from:ted",
|
|
|
|
"is:unread from:ted@zulip.com",
|
|
|
|
"is:unread",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
// Users can enter bizarre queries, and if they do, we want to
|
|
|
|
// be conservative with suggestions.
|
|
|
|
query = 'is:private near:3';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"is:private near:3",
|
|
|
|
"is:private",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'pm-with:ted@zulip.com near:3';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"pm-with:ted@zulip.com near:3",
|
|
|
|
"pm-with:ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
// Make sure suggestions still work if preceding tokens
|
|
|
|
query = 'is:alerted sender:ted@zulip.com';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"is:alerted sender:ted@zulip.com",
|
|
|
|
"is:alerted",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'is:starred has:link is:private al';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"is:starred has:link is:private al",
|
|
|
|
"is:starred has:link is:private is:alerted",
|
|
|
|
"is:starred has:link is:private sender:alice@zulip.com",
|
|
|
|
"is:starred has:link is:private pm-with:alice@zulip.com",
|
|
|
|
"is:starred has:link is:private group-pm-with:alice@zulip.com",
|
|
|
|
"is:starred has:link is:private",
|
|
|
|
"is:starred has:link",
|
|
|
|
"is:starred",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
// Make sure it handles past context correctly
|
|
|
|
query = 'stream:Denmark pm-with:';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'stream:Denmark pm-with:',
|
|
|
|
'stream:Denmark',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'sender:ted@zulip.com sender:';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'sender:ted@zulip.com sender:',
|
|
|
|
'sender:ted@zulip.com',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
});
|
|
|
|
|
|
|
|
run_test('group_suggestions', () => {
|
|
|
|
global.stream_data.subscribed_streams = function () {
|
|
|
|
return [];
|
|
|
|
};
|
|
|
|
|
|
|
|
global.narrow_state.stream = function () {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
set_global('activity', {
|
|
|
|
get_huddles: function () {
|
|
|
|
return [];
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const ted =
|
2018-07-14 12:46:02 +02:00
|
|
|
{
|
|
|
|
email: 'ted@zulip.com',
|
|
|
|
user_id: 101,
|
|
|
|
full_name: 'Ted Smith',
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const alice =
|
2018-07-14 12:46:02 +02:00
|
|
|
{
|
|
|
|
email: 'alice@zulip.com',
|
|
|
|
user_id: 102,
|
|
|
|
full_name: 'Alice Ignore',
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const jeff =
|
2018-07-14 12:46:02 +02:00
|
|
|
{
|
|
|
|
email: 'jeff@zulip.com',
|
|
|
|
user_id: 103,
|
|
|
|
full_name: 'Jeff Zoolipson',
|
|
|
|
};
|
|
|
|
|
|
|
|
people.add(ted);
|
|
|
|
people.add(alice);
|
|
|
|
people.add(jeff);
|
|
|
|
|
|
|
|
// Entering a comma in a pm-with query should immediately generate
|
|
|
|
// suggestions for the next person.
|
2019-11-02 00:06:25 +01:00
|
|
|
let query = 'pm-with:bob@zulip.com,';
|
|
|
|
let suggestions = search.get_suggestions_legacy(query);
|
|
|
|
let expected = [
|
2018-07-14 12:46:02 +02:00
|
|
|
"pm-with:bob@zulip.com,",
|
|
|
|
"pm-with:bob@zulip.com,alice@zulip.com",
|
|
|
|
"pm-with:bob@zulip.com,jeff@zulip.com",
|
|
|
|
"pm-with:bob@zulip.com,ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
// Only the last part of a comma-separated pm-with query should be used to
|
|
|
|
// generate suggestions.
|
|
|
|
query = 'pm-with:bob@zulip.com,t';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"pm-with:bob@zulip.com,t",
|
|
|
|
"pm-with:bob@zulip.com,ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
// Smit should also generate ted@zulip.com (Ted Smith) as a suggestion.
|
|
|
|
query = 'pm-with:bob@zulip.com,Smit';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"pm-with:bob@zulip.com,Smit",
|
|
|
|
"pm-with:bob@zulip.com,ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
// Do not suggest "bob@zulip.com" (the name of the current user)
|
|
|
|
query = 'pm-with:ted@zulip.com,bo';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"pm-with:ted@zulip.com,bo",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
// No superfluous suggestions should be generated.
|
|
|
|
query = 'pm-with:bob@zulip.com,red';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"pm-with:bob@zulip.com,red",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
// is:private should be properly prepended to each suggestion if the pm-with
|
|
|
|
// operator is negated.
|
|
|
|
|
|
|
|
query = '-pm-with:bob@zulip.com,';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"-pm-with:bob@zulip.com,",
|
|
|
|
"is:private -pm-with:bob@zulip.com,alice@zulip.com",
|
|
|
|
"is:private -pm-with:bob@zulip.com,jeff@zulip.com",
|
|
|
|
"is:private -pm-with:bob@zulip.com,ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = '-pm-with:bob@zulip.com,t';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"-pm-with:bob@zulip.com,t",
|
|
|
|
"is:private -pm-with:bob@zulip.com,ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = '-pm-with:bob@zulip.com,Smit';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"-pm-with:bob@zulip.com,Smit",
|
|
|
|
"is:private -pm-with:bob@zulip.com,ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = '-pm-with:bob@zulip.com,red';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"-pm-with:bob@zulip.com,red",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
// Test multiple operators
|
|
|
|
query = 'is:starred has:link pm-with:bob@zulip.com,Smit';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"is:starred has:link pm-with:bob@zulip.com,Smit",
|
|
|
|
"is:starred has:link pm-with:bob@zulip.com,ted@zulip.com",
|
|
|
|
"is:starred has:link",
|
|
|
|
"is:starred",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'stream:Denmark has:link pm-with:bob@zulip.com,Smit';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"stream:Denmark has:link pm-with:bob@zulip.com,Smit",
|
|
|
|
"stream:Denmark has:link",
|
|
|
|
"stream:Denmark",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
set_global('activity', {
|
|
|
|
get_huddles: function () {
|
|
|
|
return ['101,42', '101,103,42'];
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
// Simulate a past huddle which should now prioritize ted over alice
|
|
|
|
query = 'pm-with:bob@zulip.com,';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"pm-with:bob@zulip.com,",
|
|
|
|
"pm-with:bob@zulip.com,ted@zulip.com",
|
|
|
|
"pm-with:bob@zulip.com,alice@zulip.com",
|
|
|
|
"pm-with:bob@zulip.com,jeff@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
// bob,ted,jeff is already an existing huddle, so prioritize this one
|
|
|
|
query = 'pm-with:bob@zulip.com,ted@zulip.com,';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"pm-with:bob@zulip.com,ted@zulip.com,",
|
|
|
|
"pm-with:bob@zulip.com,ted@zulip.com,jeff@zulip.com",
|
|
|
|
"pm-with:bob@zulip.com,ted@zulip.com,alice@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
// bob,ted,jeff is already an existing huddle, but if we start with just bob,
|
|
|
|
// then don't prioritize ted over alice because it doesn't complete the full huddle.
|
|
|
|
query = 'pm-with:jeff@zulip.com,';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"pm-with:jeff@zulip.com,",
|
|
|
|
"pm-with:jeff@zulip.com,alice@zulip.com",
|
|
|
|
"pm-with:jeff@zulip.com,ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
2019-06-27 19:16:55 +02:00
|
|
|
|
|
|
|
query = "pm-with:jeff@zulip.com,ted@zulip.com hi";
|
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
|
|
|
expected = [
|
|
|
|
"pm-with:jeff@zulip.com,ted@zulip.com hi",
|
|
|
|
"pm-with:jeff@zulip.com,ted@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
2018-07-14 12:46:02 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
init();
|
|
|
|
|
|
|
|
run_test('empty_query_suggestions', () => {
|
2019-11-02 00:06:25 +01:00
|
|
|
const query = '';
|
2018-07-14 12:46:02 +02:00
|
|
|
|
|
|
|
global.stream_data.subscribed_streams = function () {
|
|
|
|
return ['devel', 'office'];
|
|
|
|
};
|
|
|
|
|
|
|
|
global.narrow_state.stream = function () {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const expected = [
|
2018-07-14 12:46:02 +02:00
|
|
|
"",
|
2019-08-13 20:20:36 +02:00
|
|
|
"streams:public",
|
2018-07-14 12:46:02 +02:00
|
|
|
"is:private",
|
|
|
|
"is:starred",
|
|
|
|
"is:mentioned",
|
|
|
|
"is:alerted",
|
|
|
|
"is:unread",
|
|
|
|
"sender:bob@zulip.com",
|
|
|
|
"stream:devel",
|
|
|
|
"stream:office",
|
|
|
|
'has:link',
|
|
|
|
'has:image',
|
|
|
|
'has:attachment',
|
|
|
|
];
|
|
|
|
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
function describe(q) {
|
2020-02-12 06:58:20 +01:00
|
|
|
return suggestions.lookup_table.get(q).description;
|
2018-07-14 12:46:02 +02:00
|
|
|
}
|
|
|
|
assert.equal(describe('is:private'), 'Private messages');
|
|
|
|
assert.equal(describe('is:starred'), 'Starred messages');
|
|
|
|
assert.equal(describe('is:mentioned'), '@-mentions');
|
|
|
|
assert.equal(describe('is:alerted'), 'Alerted messages');
|
|
|
|
assert.equal(describe('is:unread'), 'Unread messages');
|
|
|
|
assert.equal(describe('sender:bob@zulip.com'), 'Sent by me');
|
|
|
|
assert.equal(describe('has:link'), 'Messages with one or more link');
|
|
|
|
assert.equal(describe('has:image'), 'Messages with one or more image');
|
|
|
|
assert.equal(describe('has:attachment'), 'Messages with one or more attachment');
|
|
|
|
});
|
|
|
|
|
|
|
|
run_test('has_suggestions', () => {
|
|
|
|
// Checks that category wise suggestions are displayed instead of a single
|
|
|
|
// default suggestion when suggesting `has` operator.
|
2019-11-02 00:06:25 +01:00
|
|
|
let query = 'h';
|
2018-07-14 12:46:02 +02:00
|
|
|
global.stream_data.subscribed_streams = function () {
|
|
|
|
return ['devel', 'office'];
|
|
|
|
};
|
|
|
|
global.narrow_state.stream = function () {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
let suggestions = search.get_suggestions_legacy(query);
|
|
|
|
let expected = [
|
2018-07-14 12:46:02 +02:00
|
|
|
"h",
|
|
|
|
'has:link',
|
|
|
|
'has:image',
|
|
|
|
'has:attachment',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
function describe(q) {
|
2020-02-12 06:58:20 +01:00
|
|
|
return suggestions.lookup_table.get(q).description;
|
2018-07-14 12:46:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
assert.equal(describe('has:link'), 'Messages with one or more link');
|
|
|
|
assert.equal(describe('has:image'), 'Messages with one or more image');
|
|
|
|
assert.equal(describe('has:attachment'), 'Messages with one or more attachment');
|
|
|
|
|
|
|
|
query = '-h';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"-h",
|
|
|
|
'-has:link',
|
|
|
|
'-has:image',
|
|
|
|
'-has:attachment',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
assert.equal(describe('-has:link'), 'Exclude messages with one or more link');
|
|
|
|
assert.equal(describe('-has:image'), 'Exclude messages with one or more image');
|
|
|
|
assert.equal(describe('-has:attachment'), 'Exclude messages with one or more attachment');
|
|
|
|
|
|
|
|
// operand suggestions follow.
|
|
|
|
|
|
|
|
query = 'has:';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'has:link',
|
|
|
|
'has:image',
|
|
|
|
'has:attachment',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'has:im';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'has:image',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = '-has:im';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'-has:image',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'att';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'att',
|
|
|
|
'has:attachment',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'stream:Denmark is:alerted has:lin';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'stream:Denmark is:alerted has:link',
|
|
|
|
'stream:Denmark is:alerted',
|
|
|
|
'stream:Denmark',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
});
|
|
|
|
|
|
|
|
run_test('check_is_suggestions', () => {
|
2019-11-02 00:06:25 +01:00
|
|
|
let query = 'i';
|
2018-07-14 12:46:02 +02:00
|
|
|
global.stream_data.subscribed_streams = function () {
|
|
|
|
return ['devel', 'office'];
|
|
|
|
};
|
|
|
|
global.narrow_state.stream = function () {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
let suggestions = search.get_suggestions_legacy(query);
|
|
|
|
let expected = [
|
2018-07-14 12:46:02 +02:00
|
|
|
'i',
|
|
|
|
'is:private',
|
|
|
|
'is:starred',
|
|
|
|
'is:mentioned',
|
|
|
|
'is:alerted',
|
|
|
|
'is:unread',
|
|
|
|
'has:image',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
function describe(q) {
|
2020-02-12 06:58:20 +01:00
|
|
|
return suggestions.lookup_table.get(q).description;
|
2018-07-14 12:46:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
assert.equal(describe('is:private'), 'Private messages');
|
|
|
|
assert.equal(describe('is:starred'), 'Starred messages');
|
|
|
|
assert.equal(describe('is:mentioned'), '@-mentions');
|
|
|
|
assert.equal(describe('is:alerted'), 'Alerted messages');
|
|
|
|
assert.equal(describe('is:unread'), 'Unread messages');
|
|
|
|
|
|
|
|
query = '-i';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'-i',
|
|
|
|
'-is:private',
|
|
|
|
'-is:starred',
|
|
|
|
'-is:mentioned',
|
|
|
|
'-is:alerted',
|
|
|
|
'-is:unread',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
assert.equal(describe('-is:private'), 'Exclude private messages');
|
|
|
|
assert.equal(describe('-is:starred'), 'Exclude starred messages');
|
|
|
|
assert.equal(describe('-is:mentioned'), 'Exclude @-mentions');
|
|
|
|
assert.equal(describe('-is:alerted'), 'Exclude alerted messages');
|
|
|
|
assert.equal(describe('-is:unread'), 'Exclude unread messages');
|
|
|
|
|
|
|
|
// operand suggestions follow.
|
|
|
|
|
|
|
|
query = 'is:';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'is:private',
|
|
|
|
'is:starred',
|
|
|
|
'is:mentioned',
|
|
|
|
'is:alerted',
|
|
|
|
'is:unread',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'is:st';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'is:starred',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = '-is:st';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'-is:starred',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'st';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'st',
|
2019-08-13 20:20:36 +02:00
|
|
|
'streams:public',
|
2018-07-14 12:46:02 +02:00
|
|
|
'is:starred',
|
|
|
|
'stream:',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'stream:Denmark has:link is:sta';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'stream:Denmark has:link is:starred',
|
|
|
|
'stream:Denmark has:link',
|
|
|
|
'stream:Denmark',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
});
|
|
|
|
|
|
|
|
run_test('sent_by_me_suggestions', () => {
|
|
|
|
global.stream_data.subscribed_streams = function () {
|
|
|
|
return [];
|
|
|
|
};
|
|
|
|
|
|
|
|
global.narrow_state.stream = function () {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
let query = '';
|
|
|
|
let suggestions = search.get_suggestions_legacy(query);
|
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-08 04:55:06 +01:00
|
|
|
assert(suggestions.strings.includes('sender:bob@zulip.com'));
|
2020-02-12 06:58:20 +01:00
|
|
|
assert.equal(suggestions.lookup_table.get('sender:bob@zulip.com').description,
|
2018-07-14 12:46:02 +02:00
|
|
|
'Sent by me');
|
|
|
|
|
|
|
|
query = 'sender';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2019-11-02 00:06:25 +01:00
|
|
|
let expected = [
|
2018-07-14 12:46:02 +02:00
|
|
|
"sender",
|
|
|
|
"sender:bob@zulip.com",
|
|
|
|
"sender:",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = '-sender';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"-sender",
|
|
|
|
"-sender:bob@zulip.com",
|
|
|
|
"-sender:",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'from';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"from",
|
|
|
|
"from:bob@zulip.com",
|
|
|
|
"from:",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = '-from';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"-from",
|
|
|
|
"-from:bob@zulip.com",
|
|
|
|
"-from:",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'sender:bob@zulip.com';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"sender:bob@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'from:bob@zulip.com';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"from:bob@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'sent';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"sent",
|
|
|
|
"sender:bob@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = '-sent';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"-sent",
|
|
|
|
"-sender:bob@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'stream:Denmark topic:Denmark1 sent';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"stream:Denmark topic:Denmark1 sent",
|
|
|
|
"stream:Denmark topic:Denmark1 sender:bob@zulip.com",
|
|
|
|
"stream:Denmark topic:Denmark1",
|
|
|
|
"stream:Denmark",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'is:starred sender:m';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"is:starred sender:m",
|
|
|
|
"is:starred sender:bob@zulip.com",
|
|
|
|
"is:starred",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'sender:alice@zulip.com sender:';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"sender:alice@zulip.com sender:",
|
|
|
|
"sender:alice@zulip.com",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
});
|
|
|
|
|
|
|
|
run_test('topic_suggestions', () => {
|
2019-11-02 00:06:25 +01:00
|
|
|
let suggestions;
|
|
|
|
let expected;
|
2018-07-14 12:46:02 +02:00
|
|
|
|
|
|
|
global.stream_data.subscribed_streams = function () {
|
|
|
|
return ['office'];
|
|
|
|
};
|
|
|
|
|
|
|
|
global.narrow_state.stream = function () {
|
|
|
|
return 'office';
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const devel_id = 44;
|
|
|
|
const office_id = 77;
|
2018-07-14 12:46:02 +02:00
|
|
|
|
|
|
|
global.stream_data.get_stream_id = function (stream_name) {
|
|
|
|
switch (stream_name) {
|
|
|
|
case 'office': return office_id;
|
|
|
|
case 'devel': return devel_id;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-03-22 18:40:05 +01:00
|
|
|
stream_topic_history.reset();
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy('te');
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"te",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
2020-03-22 18:40:05 +01:00
|
|
|
stream_topic_history.add_message({
|
2018-07-14 12:46:02 +02:00
|
|
|
stream_id: devel_id,
|
|
|
|
topic_name: 'REXX',
|
|
|
|
});
|
|
|
|
|
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-06 06:19:47 +01:00
|
|
|
for (const topic_name of ['team', 'ignore', 'test']) {
|
2020-03-22 18:40:05 +01:00
|
|
|
stream_topic_history.add_message({
|
2018-07-14 12:46:02 +02:00
|
|
|
stream_id: office_id,
|
|
|
|
topic_name: topic_name,
|
|
|
|
});
|
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-06 06:19:47 +01:00
|
|
|
}
|
2018-07-14 12:46:02 +02:00
|
|
|
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy('te');
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"te",
|
|
|
|
"stream:office topic:team",
|
|
|
|
"stream:office topic:test",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
function describe(q) {
|
2020-02-12 06:58:20 +01:00
|
|
|
return suggestions.lookup_table.get(q).description;
|
2018-07-14 12:46:02 +02:00
|
|
|
}
|
|
|
|
assert.equal(describe('te'), "Search for te");
|
|
|
|
assert.equal(describe('stream:office topic:team'), "Stream office > team");
|
|
|
|
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy('topic:staplers stream:office');
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'topic:staplers stream:office',
|
|
|
|
'topic:staplers',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy('stream:devel topic:');
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'stream:devel topic:',
|
|
|
|
'stream:devel topic:REXX',
|
|
|
|
'stream:devel',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy('stream:devel -topic:');
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'stream:devel -topic:',
|
|
|
|
'stream:devel -topic:REXX',
|
|
|
|
'stream:devel',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy('-topic:te');
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'-topic:te',
|
|
|
|
'stream:office -topic:team',
|
|
|
|
'stream:office -topic:test',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy('is:alerted stream:devel is:starred topic:');
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'is:alerted stream:devel is:starred topic:',
|
|
|
|
'is:alerted stream:devel is:starred topic:REXX',
|
|
|
|
'is:alerted stream:devel is:starred',
|
|
|
|
'is:alerted stream:devel',
|
|
|
|
'is:alerted',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy('is:private stream:devel topic:');
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'is:private stream:devel topic:',
|
|
|
|
'is:private stream:devel',
|
|
|
|
'is:private',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy('topic:REXX stream:devel topic:');
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'topic:REXX stream:devel topic:',
|
|
|
|
'topic:REXX stream:devel',
|
|
|
|
'topic:REXX',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
});
|
|
|
|
|
|
|
|
run_test('whitespace_glitch', () => {
|
2019-11-02 00:06:25 +01:00
|
|
|
const query = 'stream:office '; // note trailing space
|
2018-07-14 12:46:02 +02:00
|
|
|
|
|
|
|
global.stream_data.subscribed_streams = function () {
|
|
|
|
return ['office'];
|
|
|
|
};
|
|
|
|
|
|
|
|
global.narrow_state.stream = function () {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
2020-03-22 18:40:05 +01:00
|
|
|
stream_topic_history.reset();
|
2018-07-14 12:46:02 +02:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const expected = [
|
2018-07-14 12:46:02 +02:00
|
|
|
"stream:office",
|
|
|
|
];
|
|
|
|
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
});
|
|
|
|
|
|
|
|
run_test('stream_completion', () => {
|
|
|
|
global.stream_data.subscribed_streams = function () {
|
|
|
|
return ['office', 'dev help'];
|
|
|
|
};
|
|
|
|
|
|
|
|
global.narrow_state.stream = function () {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
2020-03-22 18:40:05 +01:00
|
|
|
stream_topic_history.reset();
|
2018-07-14 12:46:02 +02:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
let query = 'stream:of';
|
|
|
|
let suggestions = search.get_suggestions_legacy(query);
|
|
|
|
let expected = [
|
2018-07-14 12:46:02 +02:00
|
|
|
"stream:of",
|
|
|
|
"stream:office",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = '-stream:of';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"-stream:of",
|
|
|
|
"-stream:office",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'hel';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"hel",
|
|
|
|
"stream:dev+help",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
});
|
|
|
|
|
|
|
|
run_test('people_suggestions', () => {
|
2019-11-02 00:06:25 +01:00
|
|
|
let query = 'te';
|
2018-07-14 12:46:02 +02:00
|
|
|
|
|
|
|
global.stream_data.subscribed_streams = function () {
|
|
|
|
return [];
|
|
|
|
};
|
|
|
|
|
|
|
|
global.narrow_state.stream = function () {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const ted = {
|
2018-07-14 12:46:02 +02:00
|
|
|
email: 'ted@zulip.com',
|
|
|
|
user_id: 201,
|
|
|
|
full_name: 'Ted Smith',
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const bob = {
|
2018-07-14 12:46:02 +02:00
|
|
|
email: 'bob@zulip.com',
|
|
|
|
user_id: 202,
|
|
|
|
full_name: 'Bob Térry',
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const alice = {
|
2018-07-14 12:46:02 +02:00
|
|
|
email: 'alice@zulip.com',
|
|
|
|
user_id: 203,
|
|
|
|
full_name: 'Alice Ignore',
|
|
|
|
};
|
|
|
|
people.add(ted);
|
|
|
|
people.add(bob);
|
|
|
|
people.add(alice);
|
|
|
|
|
2020-03-22 18:40:05 +01:00
|
|
|
|
|
|
|
stream_topic_history.reset();
|
2018-07-14 12:46:02 +02:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
let suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
let expected = [
|
2018-07-14 12:46:02 +02:00
|
|
|
"te",
|
|
|
|
"sender:bob@zulip.com",
|
|
|
|
"sender:ted@zulip.com",
|
|
|
|
"pm-with:bob@zulip.com", // bob térry
|
|
|
|
"pm-with:ted@zulip.com",
|
|
|
|
"group-pm-with:bob@zulip.com",
|
|
|
|
"group-pm-with:ted@zulip.com",
|
|
|
|
];
|
|
|
|
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
function describe(q) {
|
2020-02-12 06:58:20 +01:00
|
|
|
return suggestions.lookup_table.get(q).description;
|
2018-07-14 12:46:02 +02:00
|
|
|
}
|
|
|
|
assert.equal(describe('pm-with:ted@zulip.com'),
|
|
|
|
"Private messages with <strong>Te</strong>d Smith <<strong>te</strong>d@zulip.com>");
|
|
|
|
assert.equal(describe('sender:ted@zulip.com'),
|
|
|
|
"Sent by <strong>Te</strong>d Smith <<strong>te</strong>d@zulip.com>");
|
|
|
|
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy('Ted '); // note space
|
2018-07-14 12:46:02 +02:00
|
|
|
|
|
|
|
expected = [
|
|
|
|
"Ted",
|
|
|
|
"sender:ted@zulip.com",
|
|
|
|
"pm-with:ted@zulip.com",
|
|
|
|
"group-pm-with:ted@zulip.com",
|
|
|
|
];
|
|
|
|
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'sender:ted sm';
|
|
|
|
expected = [
|
|
|
|
'sender:ted+sm',
|
|
|
|
'sender:ted@zulip.com',
|
|
|
|
];
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'sender:ted@zulip.com new';
|
|
|
|
expected = [
|
|
|
|
'sender:ted@zulip.com new',
|
|
|
|
'sender:ted@zulip.com',
|
|
|
|
];
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'sender:ted@tulip.com new';
|
|
|
|
expected = [
|
|
|
|
'sender:ted@tulip.com+new',
|
|
|
|
];
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
});
|
|
|
|
|
|
|
|
run_test('operator_suggestions', () => {
|
|
|
|
// Completed operator should return nothing
|
2019-11-02 00:06:25 +01:00
|
|
|
let query = 'stream:';
|
|
|
|
let suggestions = search.get_suggestions_legacy(query);
|
|
|
|
let expected = [
|
2018-07-14 12:46:02 +02:00
|
|
|
'stream:',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'st';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'st',
|
2019-08-13 20:20:36 +02:00
|
|
|
'streams:public',
|
2018-07-14 12:46:02 +02:00
|
|
|
'is:starred',
|
|
|
|
'stream:',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'group-';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'group-',
|
|
|
|
'group-pm-with:',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = '-s';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'-s',
|
2019-08-13 20:20:36 +02:00
|
|
|
'-streams:public',
|
2018-07-14 12:46:02 +02:00
|
|
|
'-sender:bob@zulip.com',
|
|
|
|
'-stream:',
|
|
|
|
'-sender:',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
query = 'stream:Denmark is:alerted -f';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
'stream:Denmark is:alerted -f',
|
|
|
|
'stream:Denmark is:alerted -from:bob@zulip.com',
|
|
|
|
'stream:Denmark is:alerted -from:',
|
|
|
|
'stream:Denmark is:alerted',
|
|
|
|
'stream:Denmark',
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
});
|
|
|
|
|
|
|
|
run_test('queries_with_spaces', () => {
|
|
|
|
global.stream_data.subscribed_streams = function () {
|
|
|
|
return ['office', 'dev help'];
|
|
|
|
};
|
|
|
|
|
|
|
|
global.narrow_state.stream = function () {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
2020-03-22 18:40:05 +01:00
|
|
|
stream_topic_history.reset();
|
2018-07-14 12:46:02 +02:00
|
|
|
|
|
|
|
// test allowing spaces with quotes surrounding operand
|
2019-11-02 00:06:25 +01:00
|
|
|
let query = 'stream:"dev he"';
|
|
|
|
let suggestions = search.get_suggestions_legacy(query);
|
|
|
|
let expected = [
|
2018-07-14 12:46:02 +02:00
|
|
|
"stream:dev+he",
|
|
|
|
"stream:dev+help",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
// test mismatched quote
|
|
|
|
query = 'stream:"dev h';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"stream:dev+h",
|
|
|
|
"stream:dev+help",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
|
|
|
|
// test extra space after operator still works
|
|
|
|
query = 'stream: offi';
|
2018-07-14 13:01:21 +02:00
|
|
|
suggestions = search.get_suggestions_legacy(query);
|
2018-07-14 12:46:02 +02:00
|
|
|
expected = [
|
|
|
|
"stream:offi",
|
|
|
|
"stream:office",
|
|
|
|
];
|
|
|
|
assert.deepEqual(suggestions.strings, expected);
|
|
|
|
});
|