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,51 @@ 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 === Object ( obj )
24+
25+ const findICUErrors = (
26+ locales : { [ key : string ] : string } ,
27+ filePath : string ,
28+ ) : ErrorsICU => {
29+ const keys = Object . keys ( locales )
30+
31+ const errors = keys
32+ . map ( key => {
33+ const value = locales [ key ]
34+
35+ try {
36+ parse ( value )
37+
38+ return undefined
39+ } catch ( err ) {
40+ const { message } = err as ParserError
41+
42+ return {
43+ message,
44+ value,
45+ key,
46+ filePath,
47+ }
48+ }
49+ } )
50+ . filter ( x => x )
51+
52+ return errors
3153}
3254
33- const readFiles = async ( files : string [ ] ) => {
55+ const readFiles = async ( files : string [ ] ) : Promise < ErrorsICU > => {
56+ const errors = [ ]
57+
3458 for await ( const file of files ) {
3559 const extension = file . split ( '.' ) . pop ( )
3660
@@ -39,9 +63,10 @@ const readFiles = async (files: string[]) => {
3963 const data = await readFile ( file )
4064 const jsonFile = data . toString ( )
4165
42- const locales = JSON . parse ( jsonFile ) as Record < string , string >
66+ const locales = JSON . parse ( jsonFile ) as Locales
4367
44- findICUError ( locales , file )
68+ const ICUErrors = findICUErrors ( locales , file )
69+ errors . push ( ...ICUErrors )
4570 } catch ( err ) {
4671 error ( { file, err } )
4772 }
@@ -52,37 +77,44 @@ const readFiles = async (files: string[]) => {
5277 const data = await readFile ( file )
5378 const javascriptFile = data . toString ( )
5479
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- )
60-
61- if ( typeof d . default === 'object' ) {
62- findICUError ( d . default , file )
80+ const mod : unknown = await importFromString ( javascriptFile , {
81+ transformOptions : { loader : 'ts' } ,
82+ } )
83+
84+ if ( isObject ( mod ) ) {
85+ if ( 'default' in Object ( mod ) ) {
86+ const { default : locales } = mod as { default : Locales }
87+ const ICUErrors = findICUErrors ( locales , file )
88+ errors . push ( ...ICUErrors )
89+ } else {
90+ error ( 'export default from: ' , file, ' is not an object' )
91+ }
6392 } else {
64- error ( 'export default from: ' , file , ' is not an object' )
93+ error ( file , ' is not an object' )
6594 }
6695 } catch ( err ) {
6796 error ( { err, file } )
6897 }
6998 }
7099 }
100+
101+ return errors
71102}
72103
73104const files = await globby ( pattern )
74105
75- if ( files . length > 0 ) {
76- table ( files )
77- await readFiles ( files )
78- }
79-
80106if ( files . length === 0 ) {
81- info ( 'There is no files matching this pattern' , pattern )
107+ error ( 'There is no files matching this pattern' , pattern )
108+ process . exit ( 1 )
82109}
83110
84- if ( isICUError ) {
111+ table ( files )
112+
113+ const errors = await readFiles ( files )
114+
115+ if ( errors . length > 0 ) {
116+ error ( {
117+ errors,
118+ } )
85119 process . exit ( 1 )
86- } else {
87- process . exit ( 0 )
88120}
0 commit comments