Skip to content

Commit 24211fb

Browse files
committed
flow: Mark message- and realm-emoji-related types read-only and exact.
We basically make the assumption throughout our codebase that we don't mutate data like these; this lets us propagate that assumption through and have it checked by machine.
1 parent e764347 commit 24211fb

File tree

7 files changed

+34
-31
lines changed

7 files changed

+34
-31
lines changed

src/api/apiTypes.js

+22-22
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ export type DevUser = {
2828
export type ReactionType = 'unicode_emoji' | 'realm_emoji' | 'zulip_extra_emoji';
2929

3030
/** An emoji reaction to a message. */
31-
export type Reaction = {
32-
user: {
31+
export type Reaction = $ReadOnly<{|
32+
user: $ReadOnly<{|
3333
email: string,
3434
full_name: string,
3535
user_id: number,
36-
},
36+
|}>,
3737
emoji_name: string,
3838
reaction_type: ReactionType,
3939

@@ -45,16 +45,16 @@ export type Reaction = {
4545
* https://github.com/zulip/zulip/blob/master/zerver/models.py
4646
*/
4747
emoji_code: string,
48-
};
48+
|}>;
4949

50-
export type MessageEdit = {
50+
export type MessageEdit = $ReadOnly<{|
5151
prev_content?: string,
5252
prev_rendered_content?: string,
5353
prev_rendered_content_version?: number,
5454
prev_subject?: string,
5555
timestamp: number,
5656
user_id: number,
57-
};
57+
|}>;
5858

5959
/**
6060
* A Zulip message.
@@ -91,7 +91,7 @@ export type MessageEdit = {
9191
*
9292
* See also `Outbox`.
9393
*/
94-
export type Message = {
94+
export type Message = $ReadOnly<{
9595
/** Our own flag; if true, really type `Outbox`. */
9696
isOutbox: false,
9797

@@ -115,20 +115,20 @@ export type Message = {
115115
* * Absent in the Redux `state.messages`; we move the information to a
116116
* separate subtree `state.flags`.
117117
*/
118-
flags?: string[],
118+
flags?: $ReadOnlyArray<string>,
119119

120120
/** The rest are believed to really appear in `message` events. */
121121
avatar_url: ?string,
122122
client: string,
123123
content: string,
124124
content_type: 'text/html' | 'text/markdown',
125125
display_recipient: $FlowFixMe, // `string` for type stream, else PmRecipientUser[].
126-
edit_history: MessageEdit[],
126+
edit_history: $ReadOnlyArray<MessageEdit>,
127127
gravatar_hash: string,
128128
id: number,
129129
is_me_message: boolean,
130130
last_edit_timestamp?: number,
131-
reactions: Reaction[],
131+
reactions: $ReadOnlyArray<Reaction>,
132132
recipient_id: number,
133133
sender_email: string,
134134
sender_full_name: string,
@@ -137,11 +137,11 @@ export type Message = {
137137
sender_short_name: string,
138138
stream_id: number, // FixMe: actually only for type `stream`, else absent.
139139
subject: string,
140-
subject_links: string[],
141-
submessages: Message[],
140+
subject_links: $ReadOnlyArray<string>,
141+
submessages: $ReadOnlyArray<Message>,
142142
timestamp: number,
143143
type: 'stream' | 'private',
144-
};
144+
}>;
145145

146146
export type NarrowOperator =
147147
| 'is'
@@ -154,31 +154,31 @@ export type NarrowOperator =
154154
| 'pm-with'
155155
| 'search';
156156

157-
export type NarrowElement = {
157+
export type NarrowElement = $ReadOnly<{|
158158
operand: string,
159159
operator?: NarrowOperator, // TODO type: this shouldn't be absent.
160-
};
160+
|}>;
161161

162-
export type Narrow = NarrowElement[];
162+
export type Narrow = $ReadOnlyArray<NarrowElement>;
163163

164-
export type RealmEmojiType = {
165-
author: {
164+
export type RealmEmojiType = $ReadOnly<{|
165+
author: $ReadOnly<{|
166166
email: string,
167167
full_name: string,
168168
id: number,
169-
},
169+
|}>,
170170
deactivated: boolean,
171171
id: number,
172172
name: string,
173173
source_url: string,
174174
// This prevents accidentally using this type as a map.
175175
// See https://github.com/facebook/flow/issues/4257#issuecomment-321951793
176176
[empty]: mixed,
177-
};
177+
|}>;
178178

179-
export type RealmEmojiState = {
179+
export type RealmEmojiState = $ReadOnly<{
180180
[id: string]: RealmEmojiType,
181-
};
181+
}>;
182182

183183
export type RealmFilter = [string, string, number];
184184

src/chat/flagsReducers.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ const initialState = {
3535

3636
const addFlagsForMessages = (
3737
state: FlagsState,
38-
messages: number[],
39-
flags?: string[],
38+
messages: $ReadOnlyArray<number>,
39+
flags?: $ReadOnlyArray<string>,
4040
): FlagsState => {
4141
if (!messages || messages.length === 0 || !flags || flags.length === 0) {
4242
return state;

src/emoji/data.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const codeToEmojiMap = unicodeEmojiNames.reduce((obj, name) => {
2626

2727
export const getFilteredEmojiNames = (
2828
query: string,
29-
activeRealmEmojiByName: { [string]: RealmEmojiType },
29+
activeRealmEmojiByName: $ReadOnly<{ [string]: RealmEmojiType }>,
3030
): string[] => {
3131
const names = [...unicodeEmojiNames, ...Object.keys(activeRealmEmojiByName)];
3232
return Array.from(new Set([...names.filter(x => x.indexOf(query) === 0).sort()]));

src/message/messageUpdates.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { Narrow } from '../types';
44

55
type Props = $ReadOnly<{
66
narrow: Narrow,
7-
messages: $ReadOnlyArray<{ id: number }>,
7+
messages: $ReadOnlyArray<$ReadOnly<{ id: number }>>,
88
}>;
99

1010
type TransitionProps = {

src/reactions/aggregateReactions.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
/* @flow strict-local */
22
import type { Reaction, AggregatedReaction } from '../types';
33

4-
export default (reactions: Reaction[], ownEmail: string): AggregatedReaction[] =>
4+
export default (
5+
reactions: $ReadOnlyArray<Reaction>,
6+
ownEmail: string,
7+
): $ReadOnlyArray<AggregatedReaction> =>
58
Array.from(
69
reactions
710
.reduce((reactionMap, x) => {

src/webview/MessageList.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export type BackgroundData = $ReadOnly<{
6464
flags: FlagsState,
6565
mute: MuteState,
6666
ownEmail: string,
67-
allRealmEmojiById: { [id: string]: RealmEmojiType },
67+
allRealmEmojiById: $ReadOnly<{ [id: string]: RealmEmojiType }>,
6868
twentyFourHourTime: boolean,
6969
subscriptions: Subscription[],
7070
}>;

src/webview/html/messageAsHtml.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const messageTagsAsHtml = (isStarred: boolean, timeEdited: number | void): strin
3030

3131
const messageReactionAsHtml = (
3232
reaction: AggregatedReaction,
33-
allRealmEmojiById: { [id: string]: RealmEmojiType },
33+
allRealmEmojiById: $ReadOnly<{ [id: string]: RealmEmojiType }>,
3434
): string =>
3535
template`<span onClick="" class="reaction${reaction.selfReacted ? ' self-voted' : ''}"
3636
data-name="${reaction.name}"
@@ -42,9 +42,9 @@ const messageReactionAsHtml = (
4242
}&nbsp;${reaction.count}</span>`;
4343

4444
const messageReactionListAsHtml = (
45-
reactions: Reaction[],
45+
reactions: $ReadOnlyArray<Reaction>,
4646
ownEmail: string,
47-
allRealmEmojiById: { [id: string]: RealmEmojiType },
47+
allRealmEmojiById: $ReadOnly<{ [id: string]: RealmEmojiType }>,
4848
): string => {
4949
if (reactions.length === 0) {
5050
return '';

0 commit comments

Comments
 (0)