1
- import fs from "fs" ;
2
- import readline from "readline" ;
3
1
import parseArgs from "minimist" ;
2
+ import { fromStdin , fromFile } from "./input" ;
4
3
import { Resource as ResourceParser } from "../lib/parser" ;
5
- import { Resource } from "../ast" ;
4
+ import { Resource , NodeType , GroupComment } from "../ast" ;
6
5
import { Bundle } from "../bundle" ;
7
6
import { ErrorKind } from "../error" ;
7
+ import { Value , StringValue , NumberValue } from "../value" ;
8
8
9
9
const argv = parseArgs ( process . argv . slice ( 2 ) , {
10
- boolean : [ "help" ] ,
10
+ boolean : [ "help" , "group" ] ,
11
11
alias : {
12
12
help : "h" ,
13
+ group : "g" ,
13
14
} ,
14
15
} ) ;
15
16
@@ -20,32 +21,41 @@ if (argv.help) {
20
21
const [ filePath ] = argv . _ ;
21
22
22
23
if ( filePath === "-" ) {
23
- parseStdin ( ) ;
24
+ fromStdin ( print ) ;
24
25
} else if ( filePath ) {
25
- parseFile ( filePath ) ;
26
+ fromFile ( filePath , print ) ;
26
27
} else {
27
28
exitHelp ( 1 ) ;
28
29
}
29
30
30
31
function exitHelp ( exitCode : number ) {
31
32
console . log ( `
32
- Usage: node --experimental-modules parse.mjs [OPTIONS] <FILE>
33
+ Usage: node format.js [OPTIONS] <FILE>
33
34
34
35
When FILE is "-", read text from stdin.
35
36
36
37
Examples:
37
38
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 -
40
41
41
42
Options:
42
43
43
44
-h, --help Display help and quit.
45
+ -g, --group Treat each group as a separate resource.
44
46
` ) ;
45
47
process . exit ( exitCode ) ;
46
48
}
47
49
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 ) {
49
59
return ResourceParser . run ( source ) . fold (
50
60
resource => resource ,
51
61
err => {
@@ -54,15 +64,20 @@ function parseFluent(source: string) {
54
64
) ;
55
65
}
56
66
57
- function format ( resource : Resource ) {
67
+ type Variables = Map < string , Value > ;
68
+
69
+ function formatResource ( resource : Resource , variables : Variables ) {
58
70
let bundle = new Bundle ( ) ;
59
71
bundle . addResource ( resource ) ;
60
72
61
73
let results = [ ] ;
62
74
for ( let entry of resource . body ) {
75
+ if ( entry . type !== NodeType . Message ) {
76
+ continue ;
77
+ }
63
78
let message = bundle . getMessage ( entry . id . name ) ;
64
79
if ( message ) {
65
- let { value, errors} = bundle . formatValue ( message , new Map ( ) ) ;
80
+ let { value, errors} = bundle . formatValue ( message , variables ) ;
66
81
results . push ( {
67
82
value,
68
83
errors : errors . map ( error => ( {
@@ -72,36 +87,63 @@ function format(resource: Resource) {
72
87
} ) ;
73
88
}
74
89
}
90
+ return results ;
91
+ }
75
92
93
+ function printAll ( source : string ) {
94
+ let resource = parseString ( source ) ;
95
+ let results = formatResource ( resource , new Map ( ) ) ;
76
96
console . log ( JSON . stringify ( results , null , 4 ) ) ;
77
97
}
78
98
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 > ;
90
102
}
91
103
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 - z A - Z ] * ) : ( s t r i n g | n u m b e r ) = ( .* ) $ / 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 ;
96
117
}
118
+ }
119
+ return variables ;
120
+ }
121
+
122
+ function printGroups ( source : string ) {
123
+ let resource = parseString ( source ) ;
97
124
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 ) ;
100
138
}
101
- } ) ;
102
- }
139
+ }
103
140
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 ) ) ;
107
149
}
0 commit comments