22
33const fs = require ( 'fs' ) ;
44
5- function countFile ( file , options ) {
5+ function countFile ( file ) {
66 try {
77 const data = fs . readFileSync ( file , 'utf8' ) ;
88
9- const lines = data . split ( '\n' ) . length ;
9+ const lines = ( data . match ( / \n / g ) || [ ] ) . length ;
1010 const words = data . split ( / \s + / ) . filter ( Boolean ) . length ;
1111 const bytes = Buffer . byteLength ( data , 'utf8' ) ;
1212
13- const results = [ ] ;
14- if ( options . lines || ( ! options . lines && ! options . words && ! options . bytes ) ) results . push ( lines ) ;
15- if ( options . words || ( ! options . lines && ! options . words && ! options . bytes ) ) results . push ( words ) ;
16- if ( options . bytes || ( ! options . lines && ! options . words && ! options . bytes ) ) results . push ( bytes ) ;
17-
18- console . log ( `${ results . join ( '\t' ) } \t${ file } ` ) ;
19-
2013 return { lines, words, bytes } ;
2114 } catch ( err ) {
2215 console . error ( `wc: ${ file } : ${ err . code === 'ENOENT' ? 'No such file or directory' : 'An error occurred' } ` ) ;
2316 process . exit ( 1 ) ;
2417 }
2518}
2619
20+ function selectedKeys ( options ) {
21+ const keys = [ ] ;
22+ if ( options . lines ) keys . push ( 'lines' ) ;
23+ if ( options . words ) keys . push ( 'words' ) ;
24+ if ( options . bytes ) keys . push ( 'bytes' ) ;
25+ return keys ;
26+ }
27+
28+ function valuesForKeys ( counts , keys ) {
29+ return keys . map ( ( key ) => counts [ key ] ) ;
30+ }
31+
32+ function printRows ( rows , keys ) {
33+ const alignColumns = keys . length > 1 || rows . length > 1 ;
34+
35+ if ( ! alignColumns ) {
36+ const [ values , name ] = rows [ 0 ] ;
37+ console . log ( `${ values [ 0 ] } ${ name } ` ) ;
38+ return ;
39+ }
40+
41+ const widths = keys . map ( ( _ , index ) => {
42+ const maxLen = Math . max ( ...rows . map ( ( [ values ] ) => String ( values [ index ] ) . length ) ) ;
43+ return Math . max ( 3 , maxLen ) ;
44+ } ) ;
45+
46+ rows . forEach ( ( [ values , name ] ) => {
47+ const formattedValues = values
48+ . map ( ( value , index ) => String ( value ) . padStart ( widths [ index ] , ' ' ) )
49+ . join ( ' ' ) ;
50+ console . log ( `${ formattedValues } ${ name } ` ) ;
51+ } ) ;
52+ }
53+
2754function main ( ) {
2855 const args = process . argv . slice ( 2 ) ;
2956 const options = {
@@ -46,6 +73,12 @@ function main() {
4673 }
4774 } ) ;
4875
76+ if ( ! options . lines && ! options . words && ! options . bytes ) {
77+ options . lines = true ;
78+ options . words = true ;
79+ options . bytes = true ;
80+ }
81+
4982 if ( files . length === 0 ) {
5083 console . error ( 'Usage: wc [-l | -w | -c] <file>...' ) ;
5184 process . exit ( 1 ) ;
@@ -54,22 +87,23 @@ function main() {
5487 let totalLines = 0 ;
5588 let totalWords = 0 ;
5689 let totalBytes = 0 ;
90+ const keys = selectedKeys ( options ) ;
91+ const rows = [ ] ;
5792
5893 files . forEach ( ( file ) => {
59- const { lines, words, bytes } = countFile ( file , options ) ;
94+ const counts = countFile ( file ) ;
95+ const { lines, words, bytes } = counts ;
6096 totalLines += lines ;
6197 totalWords += words ;
6298 totalBytes += bytes ;
99+ rows . push ( [ valuesForKeys ( counts , keys ) , file ] ) ;
63100 } ) ;
64101
65102 if ( files . length > 1 ) {
66- const totalResults = [ ] ;
67- if ( options . lines || ( ! options . lines && ! options . words && ! options . bytes ) ) totalResults . push ( totalLines ) ;
68- if ( options . words || ( ! options . lines && ! options . words && ! options . bytes ) ) totalResults . push ( totalWords ) ;
69- if ( options . bytes || ( ! options . lines && ! options . words && ! options . bytes ) ) totalResults . push ( totalBytes ) ;
70-
71- console . log ( `${ totalResults . join ( '\t' ) } \ttotal` ) ;
103+ rows . push ( [ valuesForKeys ( { lines : totalLines , words : totalWords , bytes : totalBytes } , keys ) , 'total' ] ) ;
72104 }
105+
106+ printRows ( rows , keys ) ;
73107}
74108
75109main ( ) ;
0 commit comments