Skip to content

Commit 24f99cb

Browse files
committed
Sample test fixtures
1 parent 85cd836 commit 24f99cb

File tree

9 files changed

+159
-38
lines changed

9 files changed

+159
-38
lines changed

resolver/src/ast.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export enum NodeType {
88
Variant = "Variant",
99
Pattern = "Pattern",
1010
Message = "Message",
11+
GroupComment = "GroupComment",
1112
Resource = "Resource",
1213
}
1314

@@ -71,7 +72,12 @@ export interface Message extends SyntaxNode {
7172
readonly value: Pattern | null;
7273
}
7374

75+
export interface GroupComment extends SyntaxNode {
76+
readonly type: NodeType.GroupComment;
77+
readonly content: string;
78+
}
79+
7480
export interface Resource extends SyntaxNode {
75-
readonly type: NodeType.Message;
76-
readonly body: Array<Message>;
81+
readonly type: NodeType.Resource;
82+
readonly body: Array<Message | GroupComment>;
7783
}

resolver/src/bin/format.ts

Lines changed: 76 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
import fs from "fs";
2-
import readline from "readline";
31
import parseArgs from "minimist";
2+
import {fromStdin, fromFile} from "./input";
43
import {Resource as ResourceParser} from "../lib/parser";
5-
import {Resource} from "../ast";
4+
import {Resource, NodeType, GroupComment} from "../ast";
65
import {Bundle} from "../bundle";
76
import {ErrorKind} from "../error";
7+
import {Value, StringValue, NumberValue} from "../value";
88

99
const argv = parseArgs(process.argv.slice(2), {
10-
boolean: ["help"],
10+
boolean: ["help", "group"],
1111
alias: {
1212
help: "h",
13+
group: "g",
1314
},
1415
});
1516

@@ -20,32 +21,41 @@ if (argv.help) {
2021
const [filePath] = argv._;
2122

2223
if (filePath === "-") {
23-
parseStdin();
24+
fromStdin(print);
2425
} else if (filePath) {
25-
parseFile(filePath);
26+
fromFile(filePath, print);
2627
} else {
2728
exitHelp(1);
2829
}
2930

3031
function exitHelp(exitCode: number) {
3132
console.log(`
32-
Usage: node --experimental-modules parse.mjs [OPTIONS] <FILE>
33+
Usage: node format.js [OPTIONS] <FILE>
3334
3435
When FILE is "-", read text from stdin.
3536
3637
Examples:
3738
38-
node --experimental-modules parse.mjs path/to/file.ftl
39-
cat path/to/file.ftl | node --experimental-modules parse.mjs -
39+
node format.js path/to/file.ftl
40+
cat path/to/file.ftl | node format.js -
4041
4142
Options:
4243
4344
-h, --help Display help and quit.
45+
-g, --group Treat each group as a separate resource.
4446
`);
4547
process.exit(exitCode);
4648
}
4749

48-
function parseFluent(source: string) {
50+
function print(source: string) {
51+
if (argv.group) {
52+
printGroups(source);
53+
} else {
54+
printAll(source);
55+
}
56+
}
57+
58+
function parseString(source: string) {
4959
return ResourceParser.run(source).fold(
5060
resource => resource,
5161
err => {
@@ -54,15 +64,20 @@ function parseFluent(source: string) {
5464
);
5565
}
5666

57-
function format(resource: Resource) {
67+
type Variables = Map<string, Value>;
68+
69+
function formatResource(resource: Resource, variables: Variables) {
5870
let bundle = new Bundle();
5971
bundle.addResource(resource);
6072

6173
let results = [];
6274
for (let entry of resource.body) {
75+
if (entry.type !== NodeType.Message) {
76+
continue;
77+
}
6378
let message = bundle.getMessage(entry.id.name);
6479
if (message) {
65-
let {value, errors} = bundle.formatValue(message, new Map());
80+
let {value, errors} = bundle.formatValue(message, variables);
6681
results.push({
6782
value,
6883
errors: errors.map(error => ({
@@ -72,36 +87,63 @@ function format(resource: Resource) {
7287
});
7388
}
7489
}
90+
return results;
91+
}
7592

93+
function printAll(source: string) {
94+
let resource = parseString(source);
95+
let results = formatResource(resource, new Map());
7696
console.log(JSON.stringify(results, null, 4));
7797
}
7898

79-
function parseStdin() {
80-
const rl = readline.createInterface({
81-
input: process.stdin,
82-
output: process.stdout,
83-
prompt: "fluent>",
84-
});
85-
86-
let lines: Array<string> = [];
87-
88-
rl.on("line", line => lines.push(line));
89-
rl.on("close", () => parseFormat(lines.join("\n") + "\n"));
99+
interface Group {
100+
resource: Resource;
101+
variables: Map<string, Value>;
90102
}
91103

92-
function parseFile(filePath: string) {
93-
fs.readFile(filePath, "utf8", (err: NodeJS.ErrnoException | null, content: string | Buffer) => {
94-
if (err) {
95-
throw err;
104+
const RE_VARIABLE = /^\$([a-zA-Z]*): (string|number) = (.*)$/gm;
105+
function parseVariables(comment: GroupComment) {
106+
let variables = new Map();
107+
let match;
108+
while ((match = RE_VARIABLE.exec(comment.content))) {
109+
let [, name, type, value] = match;
110+
switch (type) {
111+
case "string":
112+
variables.set(name, new StringValue(value));
113+
break;
114+
case "number":
115+
variables.set(name, new NumberValue(parseFloat(value)));
116+
break;
96117
}
118+
}
119+
return variables;
120+
}
121+
122+
function printGroups(source: string) {
123+
let resource = parseString(source);
97124

98-
if (typeof content === "string") {
99-
parseFormat(content);
125+
let groups: Array<Group> = [];
126+
for (let entry of resource.body) {
127+
if (entry.type === NodeType.GroupComment) {
128+
groups.push({
129+
resource: {
130+
type: NodeType.Resource,
131+
body: [],
132+
},
133+
variables: parseVariables(entry),
134+
});
135+
} else if (groups.length > 0) {
136+
let currentGroup = groups[groups.length - 1];
137+
currentGroup.resource.body.push(entry);
100138
}
101-
});
102-
}
139+
}
103140

104-
function parseFormat(source: string) {
105-
let resource = parseFluent(source);
106-
format(resource);
141+
let results = [];
142+
for (let group of groups) {
143+
let groupResults = formatResource(group.resource, group.variables);
144+
let lastResult = groupResults.pop();
145+
results.push(lastResult);
146+
}
147+
148+
console.log(JSON.stringify(results, null, 4));
107149
}

resolver/src/bin/input.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import fs from "fs";
2+
import readline from "readline";
3+
4+
export function fromStdin(callback: (value: string) => void) {
5+
const rl = readline.createInterface({
6+
input: process.stdin,
7+
output: process.stdout,
8+
prompt: "fluent>",
9+
});
10+
11+
let lines: Array<string> = [];
12+
13+
rl.on("line", line => lines.push(line));
14+
rl.on("close", () => callback(lines.join("\n") + "\n"));
15+
}
16+
17+
export function fromFile(filePath: string, callback: (value: string) => void) {
18+
fs.readFile(filePath, "utf8", (err: NodeJS.ErrnoException | null, content: string | Buffer) => {
19+
if (err) {
20+
throw err;
21+
}
22+
23+
if (typeof content === "string") {
24+
callback(content);
25+
}
26+
});
27+
}

resolver/src/bundle.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {Scope} from "./scope";
22
import {Value, NoneValue} from "./value";
33
import {Message} from "./message";
44
import {ScopeError} from "./error";
5-
import {Resource} from "./ast";
5+
import {Resource, NodeType} from "./ast";
66

77
export interface Formatted {
88
readonly value: string | null;
@@ -14,7 +14,9 @@ export class Bundle {
1414

1515
addResource(resource: Resource) {
1616
for (let message of resource.body) {
17-
this.messages.set(message.id.name, new Message(message));
17+
if (message.type === NodeType.Message) {
18+
this.messages.set(message.id.name, new Message(message));
19+
}
1820
}
1921
}
2022

resolver/test/fixtures/Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FTL_FIXTURES := $(wildcard *.ftl)
2+
AST_FIXTURES := $(FTL_FIXTURES:%.ftl=%.json)
3+
4+
all: $(AST_FIXTURES)
5+
6+
.PHONY: $(AST_FIXTURES)
7+
$(AST_FIXTURES): %.json: %.ftl
8+
@node ../../dist/bin/format.js --group $< \
9+
2> /dev/null \
10+
1> $@;
11+
@echo "$< → $@"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
##
2+
3+
foo = Foo
4+
bar = {foo} Bar
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[
2+
{
3+
"value": "Foo Bar",
4+
"errors": []
5+
}
6+
]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
## Unknown variable
2+
3+
hello = Hello, {$world}!
4+
5+
## Variable set to a string
6+
## $world: string = World
7+
8+
hello = Hello, {$world}!
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[
2+
{
3+
"value": "Hello, {$world}!",
4+
"errors": [
5+
{
6+
"kind": "UnknownVariable",
7+
"arg": "$world"
8+
}
9+
]
10+
},
11+
{
12+
"value": "Hello, World!",
13+
"errors": []
14+
}
15+
]

0 commit comments

Comments
 (0)