11import { EventEmitter } from 'events' ;
22import { TextFileDiffOption } from './types' ;
3- import { PathLike } from 'fs' ;
3+ import { PathLike , createReadStream } from 'fs' ;
4+ import { Interface , createInterface } from 'readline' ;
45
5- import LineByLine = require( 'n-readlines' ) ;
66import myDebug = require( 'debug' ) ;
77
88const debug = myDebug ( 'text-file-diff' ) ;
99
10- export class MyLineReader extends LineByLine {
11- val : string = '' ;
10+ export class StreamLineReader {
11+ value : string = '' ;
1212 nextValue : string = '' ;
1313 lineNumber : number = - 1 ;
14- myFile : string | undefined = undefined ;
1514 charset : any = 'utf8' ;
15+ it ?: AsyncIterableIterator < string > ;
1616 eof : number = - 1 ;
17- constructor ( file : PathLike | number ) {
18- super ( file , null ) ;
17+ async init ( readStream : NodeJS . ReadableStream ) : Promise < StreamLineReader > {
18+ const rl = createInterface ( {
19+ input : readStream ,
20+ crlfDelay : Number . POSITIVE_INFINITY
21+ } ) ;
22+ this . it = rl [ Symbol . asyncIterator ] ( ) ;
1923
2024 // move to first line
21- this . moveNext ( ) ;
22- this . moveNext ( ) ;
25+ await this . moveNext ( ) ;
26+ await this . moveNext ( ) ;
27+
28+ return this ;
2329 }
2430
25- moveNext ( ) : string {
26- this . val = this . nextValue ;
31+ async moveNext ( ) : Promise < string > {
32+ this . value = this . nextValue ;
2733
28- let nextValue : any = this . next ( ) ;
34+ const nextResult = await this . it . next ( ) ;
2935
30- if ( nextValue === false ) {
36+ if ( nextResult . done ) {
3137 this . eof ++ ;
32- nextValue = '' ;
38+ nextResult . value = '' ;
3339 }
3440
35- this . nextValue = nextValue . toString ( this . charset ) ;
41+ this . nextValue = nextResult . value ;
3642 this . lineNumber ++ ;
37- return this . val ;
43+ return this . value ;
3844 }
3945}
4046
@@ -56,42 +62,56 @@ export default class TextFileDiff extends EventEmitter {
5662 * @param String file2 path to file 2
5763 * @return Object self
5864 */
59- diff ( file1 : string , file2 : string ) {
60- const lineReader1 = new MyLineReader ( file1 ) ;
61- const lineReader2 = new MyLineReader ( file2 ) ;
65+ async diff ( file1 : string , file2 : string ) {
66+ const stream1 = createReadStream ( file1 ) ;
67+ const stream2 = createReadStream ( file2 ) ;
68+ return this . diffStream ( stream1 , stream2 ) ;
69+ }
70+
71+ /**
72+ * run diffStream
73+ * @param NodeJS.ReadableStream stream1
74+ * @param NodeJS.ReadableStream stream2
75+ * @return Object self
76+ */
77+ async diffStream ( stream1 : NodeJS . ReadableStream , stream2 : NodeJS . ReadableStream ) {
78+ const lineReader1 = await ( new StreamLineReader ( ) ) . init ( stream1 ) ;
79+ const lineReader2 = await ( new StreamLineReader ( ) ) . init ( stream2 ) ;
6280 const { compareFn, charset} = this . options ;
6381
6482 lineReader1 . charset = charset ;
6583 lineReader2 . charset = charset ;
6684
6785 if ( this . options . skipHeader ) {
68- lineReader1 . moveNext ( ) ;
69- lineReader2 . moveNext ( ) ;
86+ await lineReader1 . moveNext ( ) ;
87+ await lineReader2 . moveNext ( ) ;
7088 }
7189
90+ /* eslint-disable no-await-in-loop */
7291 // while both files has valid val, check for actual false value
7392 while ( lineReader1 . eof < 2 && lineReader2 . eof < 2 ) {
74- this . doCompareLineReader ( lineReader1 , lineReader2 ) ;
93+ await this . doCompareLineReader ( lineReader1 , lineReader2 ) ;
7594 }
95+ /* eslint-enable no-await-in-loop */
7696
7797 return this ;
7898 }
7999
80- doCompareLineReader ( lineReader1 : MyLineReader , lineReader2 : MyLineReader ) {
100+ async doCompareLineReader ( lineReader1 : StreamLineReader , lineReader2 : StreamLineReader ) {
81101 // forEach line in File1, compare to line in File2
82- const line1 = lineReader1 . val ;
83- const line2 = lineReader2 . val ;
102+ const line1 = lineReader1 . value ;
103+ const line2 = lineReader2 . value ;
84104 const cmp = this . options . compareFn ( line1 , line2 ) ;
85105
86- // debug(lineReader1.val, lineReader2.val , cmp);
106+ // debug(line1, line1 , cmp);
87107 // debug(lineReader1.nextValue, lineReader2.nextValue, 'next', lineReader1.eof, lineReader2.eof);
88108 // emit on compared
89109 this . emit ( 'compared' , line1 , line2 , cmp , lineReader1 , lineReader2 ) ;
90110
91111 // equals: incr both files to next line
92112 if ( cmp === 0 ) {
93- lineReader1 . moveNext ( ) ;
94- lineReader2 . moveNext ( ) ;
113+ await lineReader1 . moveNext ( ) ;
114+ await lineReader2 . moveNext ( ) ;
95115 } else if ( cmp > 0 ) {
96116 // line1 > line2: new line detected
97117 if ( cmp === 1 ) {
@@ -105,7 +125,7 @@ export default class TextFileDiff extends EventEmitter {
105125 }
106126
107127 // incr File2 to next line
108- lineReader2 . moveNext ( ) ;
128+ await lineReader2 . moveNext ( ) ;
109129 } else if ( cmp < 0 ) {
110130 // line1 < line2: deleted line
111131 if ( cmp === - 1 ) {
@@ -119,7 +139,7 @@ export default class TextFileDiff extends EventEmitter {
119139 }
120140
121141 // incr File1 to next line
122- lineReader1 . moveNext ( ) ;
142+ await lineReader1 . moveNext ( ) ;
123143 }
124144 }
125145}
0 commit comments