1
1
import { EventEmitter } from 'events' ;
2
2
import { TextFileDiffOption } from './types' ;
3
- import { PathLike } from 'fs' ;
3
+ import { PathLike , createReadStream } from 'fs' ;
4
+ import { Interface , createInterface } from 'readline' ;
4
5
5
- import LineByLine = require( 'n-readlines' ) ;
6
6
import myDebug = require( 'debug' ) ;
7
7
8
8
const debug = myDebug ( 'text-file-diff' ) ;
9
9
10
- export class MyLineReader extends LineByLine {
11
- val : string = '' ;
10
+ export class StreamLineReader {
11
+ value : string = '' ;
12
12
nextValue : string = '' ;
13
13
lineNumber : number = - 1 ;
14
- myFile : string | undefined = undefined ;
15
14
charset : any = 'utf8' ;
15
+ it ?: AsyncIterableIterator < string > ;
16
16
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 ] ( ) ;
19
23
20
24
// move to first line
21
- this . moveNext ( ) ;
22
- this . moveNext ( ) ;
25
+ await this . moveNext ( ) ;
26
+ await this . moveNext ( ) ;
27
+
28
+ return this ;
23
29
}
24
30
25
- moveNext ( ) : string {
26
- this . val = this . nextValue ;
31
+ async moveNext ( ) : Promise < string > {
32
+ this . value = this . nextValue ;
27
33
28
- let nextValue : any = this . next ( ) ;
34
+ const nextResult = await this . it . next ( ) ;
29
35
30
- if ( nextValue === false ) {
36
+ if ( nextResult . done ) {
31
37
this . eof ++ ;
32
- nextValue = '' ;
38
+ nextResult . value = '' ;
33
39
}
34
40
35
- this . nextValue = nextValue . toString ( this . charset ) ;
41
+ this . nextValue = nextResult . value ;
36
42
this . lineNumber ++ ;
37
- return this . val ;
43
+ return this . value ;
38
44
}
39
45
}
40
46
@@ -56,42 +62,56 @@ export default class TextFileDiff extends EventEmitter {
56
62
* @param String file2 path to file 2
57
63
* @return Object self
58
64
*/
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 ) ;
62
80
const { compareFn, charset} = this . options ;
63
81
64
82
lineReader1 . charset = charset ;
65
83
lineReader2 . charset = charset ;
66
84
67
85
if ( this . options . skipHeader ) {
68
- lineReader1 . moveNext ( ) ;
69
- lineReader2 . moveNext ( ) ;
86
+ await lineReader1 . moveNext ( ) ;
87
+ await lineReader2 . moveNext ( ) ;
70
88
}
71
89
90
+ /* eslint-disable no-await-in-loop */
72
91
// while both files has valid val, check for actual false value
73
92
while ( lineReader1 . eof < 2 && lineReader2 . eof < 2 ) {
74
- this . doCompareLineReader ( lineReader1 , lineReader2 ) ;
93
+ await this . doCompareLineReader ( lineReader1 , lineReader2 ) ;
75
94
}
95
+ /* eslint-enable no-await-in-loop */
76
96
77
97
return this ;
78
98
}
79
99
80
- doCompareLineReader ( lineReader1 : MyLineReader , lineReader2 : MyLineReader ) {
100
+ async doCompareLineReader ( lineReader1 : StreamLineReader , lineReader2 : StreamLineReader ) {
81
101
// 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 ;
84
104
const cmp = this . options . compareFn ( line1 , line2 ) ;
85
105
86
- // debug(lineReader1.val, lineReader2.val , cmp);
106
+ // debug(line1, line1 , cmp);
87
107
// debug(lineReader1.nextValue, lineReader2.nextValue, 'next', lineReader1.eof, lineReader2.eof);
88
108
// emit on compared
89
109
this . emit ( 'compared' , line1 , line2 , cmp , lineReader1 , lineReader2 ) ;
90
110
91
111
// equals: incr both files to next line
92
112
if ( cmp === 0 ) {
93
- lineReader1 . moveNext ( ) ;
94
- lineReader2 . moveNext ( ) ;
113
+ await lineReader1 . moveNext ( ) ;
114
+ await lineReader2 . moveNext ( ) ;
95
115
} else if ( cmp > 0 ) {
96
116
// line1 > line2: new line detected
97
117
if ( cmp === 1 ) {
@@ -105,7 +125,7 @@ export default class TextFileDiff extends EventEmitter {
105
125
}
106
126
107
127
// incr File2 to next line
108
- lineReader2 . moveNext ( ) ;
128
+ await lineReader2 . moveNext ( ) ;
109
129
} else if ( cmp < 0 ) {
110
130
// line1 < line2: deleted line
111
131
if ( cmp === - 1 ) {
@@ -119,7 +139,7 @@ export default class TextFileDiff extends EventEmitter {
119
139
}
120
140
121
141
// incr File1 to next line
122
- lineReader1 . moveNext ( ) ;
142
+ await lineReader1 . moveNext ( ) ;
123
143
}
124
144
}
125
145
}
0 commit comments