Skip to content

Commit 410fc19

Browse files
authored
Bug 1685565: Type @fluent/syntax (#1902)
* Type @fluent/syntax * Type @fluent/langneg * Type @fluent/bundle * Move @fluent/react typedef into fluentDef * Pick up @fluent libraries with needed type fixes * Drop bad bundle mock from tests * Better fluent typing in editor modules * Unalias FluentMessage, FluentAttribute, FluentAttributes
1 parent 5012eb8 commit 410fc19

29 files changed

+499
-197
lines changed

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ module.exports = {
6363
SyntheticMouseEvent: false,
6464
TimeoutID: false,
6565
"$Diff": false,
66+
"$ReadOnly": false,
6667
"$ReadOnlyArray": false,
6768
"React$Element": false,
6869
},

frontend/flow-typed/fluentDef.js

Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
/* @flow */
2+
3+
declare module '@fluent/bundle' {
4+
declare export class FluentResource {
5+
constructor(source: string): this;
6+
}
7+
declare export type TextTransform = (text: string) => string;
8+
declare export class FluentBundle {
9+
constructor(
10+
locales: string | Array<string>,
11+
opts?: {
12+
useIsolating?: boolean,
13+
transform?: TextTransform,
14+
},
15+
): this;
16+
addResource(
17+
res: FluentResource,
18+
opts?: {
19+
allowOverrides?: boolean,
20+
},
21+
): Array<Error>;
22+
}
23+
}
24+
25+
declare module '@fluent/langneg' {
26+
declare interface NegotiateLanguagesOptions {
27+
strategy?: 'filtering' | 'matching' | 'lookup';
28+
defaultLocale?: string;
29+
}
30+
declare export function negotiateLanguages(
31+
requestedLocales: $ReadOnlyArray<string>,
32+
availableLocales: $ReadOnlyArray<string>,
33+
opts?: NegotiateLanguagesOptions,
34+
): Array<string>;
35+
}
36+
37+
declare module '@fluent/react' {
38+
declare export class ReactLocalization {
39+
constructor(Array<any>): ReactLocalization;
40+
}
41+
42+
declare export function LocalizationProvider(
43+
props: any,
44+
): React$Element<any>;
45+
46+
declare export interface LocalizedProps {
47+
id: string;
48+
attrs?: { [string]: boolean };
49+
children?: React$Node;
50+
vars?: { [string]: any };
51+
elems?: { [string]: ?React$Element<any> };
52+
}
53+
declare export function Localized(
54+
props: LocalizedProps,
55+
): React$Element<any>;
56+
}
57+
58+
declare module '@fluent/syntax' {
59+
declare export class BaseNode {
60+
[name: string]: mixed;
61+
equals(other: BaseNode, ignoredFields?: Array<string>): boolean;
62+
clone(): this;
63+
}
64+
declare export class SyntaxNode extends BaseNode {
65+
span?: Span;
66+
addSpan(start: number, end: number): void;
67+
}
68+
declare export class Resource extends SyntaxNode {
69+
type: 'Resource';
70+
body: Array<Entry>;
71+
constructor(body?: Array<Entry>): this;
72+
}
73+
declare export type Entry = Message | Term | Comments | Junk;
74+
declare export class Message extends SyntaxNode {
75+
type: 'Message';
76+
id: Identifier;
77+
value: Pattern | null;
78+
attributes: Array<Attribute>;
79+
comment: Comment | null;
80+
constructor(
81+
id: Identifier,
82+
value?: Pattern | null,
83+
attributes?: Array<Attribute>,
84+
comment?: Comment | null,
85+
): this;
86+
}
87+
declare export class Term extends SyntaxNode {
88+
type: 'Term';
89+
id: Identifier;
90+
value: Pattern;
91+
attributes: Array<Attribute>;
92+
comment: Comment | null;
93+
constructor(
94+
id: Identifier,
95+
value: Pattern,
96+
attributes?: Array<Attribute>,
97+
comment?: Comment | null,
98+
): this;
99+
}
100+
declare export class Pattern extends SyntaxNode {
101+
type: 'Pattern';
102+
elements: Array<PatternElement>;
103+
constructor(elements: Array<PatternElement>): this;
104+
}
105+
declare export type PatternElement = TextElement | Placeable;
106+
declare export class TextElement extends SyntaxNode {
107+
type: 'TextElement';
108+
value: string;
109+
constructor(value: string): this;
110+
}
111+
declare export class Placeable extends SyntaxNode {
112+
type: 'Placeable';
113+
expression: Expression;
114+
constructor(expression: Expression): this;
115+
}
116+
/**
117+
* A subset of expressions which can be used as outside of Placeables.
118+
*/
119+
declare export type InlineExpression =
120+
| StringLiteral
121+
| NumberLiteral
122+
| FunctionReference
123+
| MessageReference
124+
| TermReference
125+
| VariableReference
126+
| Placeable;
127+
declare export type Expression = InlineExpression | SelectExpression;
128+
declare export class BaseLiteral extends SyntaxNode {
129+
value: string;
130+
constructor(value: string): this;
131+
parse(): {
132+
value: any,
133+
};
134+
}
135+
declare export class StringLiteral extends BaseLiteral {
136+
type: 'StringLiteral';
137+
parse(): {
138+
value: string,
139+
};
140+
}
141+
declare export class NumberLiteral extends BaseLiteral {
142+
type: 'NumberLiteral';
143+
parse(): {
144+
value: number,
145+
precision: number,
146+
};
147+
}
148+
declare export type Literal = StringLiteral | NumberLiteral;
149+
declare export class MessageReference extends SyntaxNode {
150+
type: 'MessageReference';
151+
id: Identifier;
152+
attribute: Identifier | null;
153+
constructor(id: Identifier, attribute?: Identifier | null): this;
154+
}
155+
declare export class TermReference extends SyntaxNode {
156+
type: 'TermReference';
157+
id: Identifier;
158+
attribute: Identifier | null;
159+
arguments: CallArguments | null;
160+
constructor(
161+
id: Identifier,
162+
attribute?: Identifier | null,
163+
args?: CallArguments | null,
164+
): this;
165+
}
166+
declare export class VariableReference extends SyntaxNode {
167+
type: 'VariableReference';
168+
id: Identifier;
169+
constructor(id: Identifier): this;
170+
}
171+
declare export class FunctionReference extends SyntaxNode {
172+
type: 'FunctionReference';
173+
id: Identifier;
174+
arguments: CallArguments;
175+
constructor(id: Identifier, args: CallArguments): this;
176+
}
177+
declare export class SelectExpression extends SyntaxNode {
178+
type: 'SelectExpression';
179+
selector: InlineExpression;
180+
variants: Array<Variant>;
181+
constructor(selector: InlineExpression, variants: Array<Variant>): this;
182+
}
183+
declare export class CallArguments extends SyntaxNode {
184+
type: 'CallArguments';
185+
positional: Array<InlineExpression>;
186+
named: Array<NamedArgument>;
187+
constructor(
188+
positional?: Array<InlineExpression>,
189+
named?: Array<NamedArgument>,
190+
): this;
191+
}
192+
declare export class Attribute extends SyntaxNode {
193+
type: 'Attribute';
194+
id: Identifier;
195+
value: Pattern;
196+
constructor(id: Identifier, value: Pattern): this;
197+
}
198+
declare export class Variant extends SyntaxNode {
199+
type: 'Variant';
200+
key: Identifier | NumberLiteral;
201+
value: Pattern;
202+
default: boolean;
203+
constructor(
204+
key: Identifier | NumberLiteral,
205+
value: Pattern,
206+
def: boolean,
207+
): this;
208+
}
209+
declare export class NamedArgument extends SyntaxNode {
210+
type: 'NamedArgument';
211+
name: Identifier;
212+
value: Literal;
213+
constructor(name: Identifier, value: Literal): this;
214+
}
215+
declare export class Identifier extends SyntaxNode {
216+
type: 'Identifier';
217+
name: string;
218+
constructor(name: string): this;
219+
}
220+
declare export class BaseComment extends SyntaxNode {
221+
content: string;
222+
constructor(content: string): this;
223+
}
224+
declare export class Comment extends BaseComment {
225+
type: 'Comment';
226+
}
227+
declare export class GroupComment extends BaseComment {
228+
type: 'GroupComment';
229+
}
230+
declare export class ResourceComment extends BaseComment {
231+
type: 'ResourceComment';
232+
}
233+
declare export type Comments = Comment | GroupComment | ResourceComment;
234+
declare export class Junk extends SyntaxNode {
235+
type: 'Junk';
236+
annotations: Array<Annotation>;
237+
content: string;
238+
constructor(content: string): this;
239+
addAnnotation(annotation: Annotation): void;
240+
}
241+
declare export class Span extends BaseNode {
242+
type: 'Span';
243+
start: number;
244+
end: number;
245+
constructor(start: number, end: number): this;
246+
}
247+
declare export class Annotation extends SyntaxNode {
248+
type: 'Annotation';
249+
code: string;
250+
arguments: Array<mixed>;
251+
message: string;
252+
constructor(code: string, args: mixed[] | void, message: string): this;
253+
}
254+
255+
/**
256+
* Parsers
257+
*/
258+
declare export interface FluentParserOptions {
259+
withSpans?: boolean;
260+
}
261+
declare export class FluentParser {
262+
withSpans: boolean;
263+
constructor(opts?: FluentParserOptions): this;
264+
parse(source: string): Resource;
265+
parseEntry(source: string): Entry;
266+
}
267+
268+
/**
269+
* Serializers
270+
*/
271+
declare export interface FluentSerializerOptions {
272+
withJunk?: boolean;
273+
}
274+
declare export class FluentSerializer {
275+
withJunk: boolean;
276+
constructor(opts?: FluentSerializerOptions): this;
277+
serialize(resource: Resource): string;
278+
serializeEntry(entry: Entry, state?: number): string;
279+
}
280+
declare export function serializeExpression(
281+
expr: Expression | Placeable,
282+
): string;
283+
declare export function serializeVariantKey(
284+
key: Identifier | NumberLiteral,
285+
): string;
286+
287+
/**
288+
* A read-and-write visitor.
289+
*
290+
* Subclasses can be used to modify an AST in-place.
291+
*
292+
* To handle specific node types add methods like `visitPattern`.
293+
* Then, to descend into children call `genericVisit`.
294+
*
295+
* Visiting methods must implement the following interface:
296+
*
297+
* interface TransformingMethod {
298+
* (this: Transformer, node: BaseNode): BaseNode | void;
299+
* }
300+
*
301+
* The returned node will replace the original one in the AST. Return
302+
* `undefined` to remove the node instead.
303+
*/
304+
declare export class Transformer {
305+
[prop: string]: mixed;
306+
visit(node: BaseNode): BaseNode | void;
307+
genericVisit(node: BaseNode): BaseNode;
308+
+visitResource?: (node: Resource) => BaseNode | void;
309+
+visitMessage?: (node: Message) => BaseNode | void;
310+
+visitTerm?: (node: Term) => BaseNode | void;
311+
+visitPattern?: (node: Pattern) => BaseNode | void;
312+
+visitTextElement?: (node: TextElement) => BaseNode | void;
313+
+visitPlaceable?: (node: Placeable) => BaseNode | void;
314+
+visitStringLiteral?: (node: StringLiteral) => BaseNode | void;
315+
+visitNumberLiteral?: (node: NumberLiteral) => BaseNode | void;
316+
+visitMessageReference?: (node: MessageReference) => BaseNode | void;
317+
+visitTermReference?: (node: TermReference) => BaseNode | void;
318+
+visitVariableReference?: (node: VariableReference) => BaseNode | void;
319+
+visitFunctionReference?: (node: FunctionReference) => BaseNode | void;
320+
+visitSelectExpression?: (node: SelectExpression) => BaseNode | void;
321+
+visitCallArguments?: (node: CallArguments) => BaseNode | void;
322+
+visitAttribute?: (node: Attribute) => BaseNode | void;
323+
+visitVariant?: (node: Variant) => BaseNode | void;
324+
+visitNamedArgument?: (node: NamedArgument) => BaseNode | void;
325+
+visitIdentifier?: (node: Identifier) => BaseNode | void;
326+
+visitComment?: (node: Comment) => BaseNode | void;
327+
+visitGroupComment?: (node: GroupComment) => BaseNode | void;
328+
+visitResourceComment?: (node: ResourceComment) => BaseNode | void;
329+
+visitJunk?: (node: Junk) => BaseNode | void;
330+
+visitSpan?: (node: Span) => BaseNode | void;
331+
+visitAnnotation?: (node: Annotation) => BaseNode | void;
332+
}
333+
}

frontend/flow-typed/myLibDef.js

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,3 @@
1-
declare module '@fluent/react' {
2-
declare export class ReactLocalization {
3-
constructor(Array<any>): ReactLocalization;
4-
}
5-
6-
declare export function LocalizationProvider(
7-
props: any,
8-
): React$Element<any>;
9-
10-
declare export interface LocalizedProps {
11-
id: string;
12-
attrs?: { [string]: boolean };
13-
children?: React$Node;
14-
vars?: { [string]: any };
15-
elems?: { [string]: ?React$Element<any> };
16-
}
17-
declare export function Localized(
18-
props: LocalizedProps,
19-
): React$Element<any>;
20-
}
21-
221
declare module 'react-content-marker' {
232
declare export type TagFunction = (input: string) => React$Element<any>;
243
declare export interface Parser {

frontend/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
"version": "0.1.0",
44
"private": true,
55
"dependencies": {
6-
"@fluent/bundle": "0.16.0",
7-
"@fluent/langneg": "0.5.0",
8-
"@fluent/react": "0.13.0",
9-
"@fluent/syntax": "0.16.1",
6+
"@fluent/bundle": "0.16.1",
7+
"@fluent/langneg": "0.5.1",
8+
"@fluent/react": "0.13.1",
9+
"@fluent/syntax": "0.17.0",
1010
"abortcontroller-polyfill": "1.3.0",
1111
"connected-react-router": "6.8.0",
1212
"date-and-time": "0.14.2",

frontend/src/core/editor/actions.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import * as unsavedchanges from 'modules/unsavedchanges';
1313

1414
import type { Entity, SourceType } from 'core/api';
1515
import type { Locale } from 'core/locale';
16-
import type { FluentMessage } from 'core/utils/fluent/types';
16+
import type { Entry } from '@fluent/syntax';
1717

1818
export const END_UPDATE_TRANSLATION: 'editor/END_UPDATE_TRANSLATION' =
1919
'editor/END_UPDATE_TRANSLATION';
@@ -40,7 +40,7 @@ export const UPDATE_SELECTION: 'editor/UPDATE_SELECTION' =
4040
export const UPDATE_MACHINERY_SOURCES: 'editor/UPDATE_MACHINERY_SOURCES' =
4141
'editor/UPDATE_MACHINERY_SOURCES';
4242

43-
export type Translation = string | FluentMessage;
43+
export type Translation = string | Entry;
4444

4545
/**
4646
* Update the current translation of the selected entity.

0 commit comments

Comments
 (0)