11#!/usr/bin/env node
22
33import { parse } from '@formatjs/icu-messageformat-parser'
4- import { info } from 'console '
4+ import { ParserError } from '@formatjs/icu-messageformat-parser/error '
55import { readFile } from 'fs/promises'
66import { globby } from 'globby'
77import { importFromString } from 'module-from-string'
@@ -10,27 +10,52 @@ const args = process.argv.slice(2)
1010const pattern = args [ 0 ]
1111const { error, table } = console
1212
13- let isICUError = false
14-
15- const findICUError = ( locales : { [ key : string ] : string } , filePath : string ) => {
16- Object . keys ( locales ) . forEach ( key => {
17- const value = locales [ key ]
18-
19- try {
20- parse ( value )
21- } catch ( err ) {
22- isICUError = true
23- error ( {
24- err,
25- value,
26- key,
27- filePath,
28- } )
29- }
30- } )
13+ type Locales = Record < string , string >
14+ type ErrorICU = {
15+ message : ParserError [ 'message' ]
16+ value : string
17+ key : string
18+ filePath : string
19+ }
20+
21+ type ErrorsICU = ( ErrorICU | undefined ) [ ]
22+
23+ const isObject = ( obj : unknown ) : obj is Record < string , unknown > =>
24+ obj = = = Object ( obj )
25+
26+ const findICUErrors = (
27+ locales : { [ key : string ] : string } ,
28+ filePath : string ,
29+ ) : ErrorsICU => {
30+ const keys = Object . keys ( locales )
31+
32+ const errors = keys
33+ . map ( key => {
34+ const value = locales [ key ]
35+
36+ try {
37+ parse ( value )
38+
39+ return undefined
40+ } catch ( err ) {
41+ const { message } = err as ParserError
42+
43+ return {
44+ message,
45+ value,
46+ key,
47+ filePath,
48+ }
49+ }
50+ } )
51+ . filter ( Boolean )
52+
53+ return errors
3154}
3255
33- const readFiles = async ( files : string [ ] ) => {
56+ const readFiles = async ( files : string [ ] ) : Promise < ErrorsICU > => {
57+ const errors = [ ]
58+
3459 for await ( const file of files ) {
3560 const extension = file . split ( '.' ) . pop ( )
3661
@@ -39,9 +64,10 @@ const readFiles = async (files: string[]) => {
3964 const data = await readFile ( file )
4065 const jsonFile = data . toString ( )
4166
42- const locales = JSON . parse ( jsonFile ) as Record < string , string >
67+ const locales = JSON . parse ( jsonFile ) as Locales
4368
44- findICUError ( locales , file )
69+ const ICUErrors = findICUErrors ( locales , file )
70+ errors . push ( ...ICUErrors )
4571 } catch ( err ) {
4672 error ( { file, err } )
4773 }
@@ -52,37 +78,45 @@ const readFiles = async (files: string[]) => {
5278 const data = await readFile ( file )
5379 const javascriptFile = data . toString ( )
5480
55- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
56- const d : { default : Record < string , string > } = await importFromString (
57- javascriptFile ,
58- { transformOptions : { loader : 'ts' } } ,
59- )
81+ const mod : unknown = await importFromString ( javascriptFile , {
82+ transformOptions : { loader : 'ts' } ,
83+ } )
84+
85+ if ( isObject ( mod ) ) {
86+ if ( 'default' in mod ) {
87+ const { default : locales } = mod as { default : Locales }
6088
61- if ( typeof d . default === 'object' ) {
62- findICUError ( d . default , file )
89+ const ICUErrors = findICUErrors ( locales , file )
90+ errors . push ( ...ICUErrors )
91+ } else {
92+ error ( 'export default from: ' , file, ' is not an object' )
93+ }
6394 } else {
64- error ( 'export default from: ' , file , ' is not an object' )
95+ error ( file , ' is not an object' )
6596 }
6697 } catch ( err ) {
6798 error ( { err, file } )
6899 }
69100 }
70101 }
102+
103+ return errors
71104}
72105
73106const files = await globby ( pattern )
74107
75- if ( files . length > 0 ) {
76- table ( files )
77- await readFiles ( files )
78- }
79-
80108if ( files . length === 0 ) {
81- info ( 'There is no files matching this pattern' , pattern )
109+ error ( 'There is no files matching this pattern' , pattern )
110+ process . exit ( 1 )
82111}
83112
84- if ( isICUError ) {
113+ table ( files )
114+
115+ const errors = await readFiles ( files )
116+
117+ if ( errors . length > 0 ) {
118+ error ( {
119+ errors,
120+ } )
85121 process . exit ( 1 )
86- } else {
87- process . exit ( 0 )
88122}
0 commit comments