Skip to content

Commit 11b65ae

Browse files
committed
convert async so we can do diffStream
1 parent fc20b90 commit 11b65ae

File tree

7 files changed

+124
-84
lines changed

7 files changed

+124
-84
lines changed

bin/text-file-diff

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env node
2-
const TextFileDiff = require('../index.js');
2+
const TextFileDiff = require('../dist/index.js').default;
33

44
const argv = process.argv;
55

@@ -23,4 +23,5 @@ lfd.on('+', line => {
2323
lfd.on('-', line => {
2424
console.log('-|' + line);
2525
});
26+
2627
lfd.diff(file1, file2);

dist/index.d.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
/// <reference types="node" />
22
import { EventEmitter } from 'events';
33
import { TextFileDiffOption } from './types';
4-
import { PathLike } from 'fs';
5-
import LineByLine = require('n-readlines');
6-
export declare class MyLineReader extends LineByLine {
7-
val: string;
4+
export declare class StreamLineReader {
5+
value: string;
86
nextValue: string;
97
lineNumber: number;
10-
myFile: string | undefined;
118
charset: any;
9+
it?: AsyncIterableIterator<string>;
1210
eof: number;
13-
constructor(file: PathLike | number);
14-
moveNext(): string;
11+
init(readStream: NodeJS.ReadableStream): Promise<StreamLineReader>;
12+
moveNext(): Promise<string>;
1513
}
1614
/**
1715
* line by line diff of two files
@@ -25,6 +23,13 @@ export default class TextFileDiff extends EventEmitter {
2523
* @param String file2 path to file 2
2624
* @return Object self
2725
*/
28-
diff(file1: string, file2: string): this;
29-
doCompareLineReader(lineReader1: MyLineReader, lineReader2: MyLineReader): void;
26+
diff(file1: string, file2: string): Promise<this>;
27+
/**
28+
* run diffStream
29+
* @param NodeJS.ReadableStream stream1
30+
* @param NodeJS.ReadableStream stream2
31+
* @return Object self
32+
*/
33+
diffStream(stream1: NodeJS.ReadableStream, stream2: NodeJS.ReadableStream): Promise<this>;
34+
doCompareLineReader(lineReader1: StreamLineReader, lineReader2: StreamLineReader): Promise<void>;
3035
}

dist/index.js

Lines changed: 52 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "text-file-diff",
3-
"version": "1.2.0",
3+
"version": "1.3.0",
44
"description": "line by line diff of two large files",
55
"license": "MIT",
66
"repository": "niiknow/text-file-diff",
@@ -30,10 +30,7 @@
3030
"compare",
3131
"compare-files"
3232
],
33-
"dependencies": {
34-
"@types/n-readlines": "^1.0.1",
35-
"n-readlines": "^1.0.1"
36-
},
33+
"dependencies": {},
3734
"devDependencies": {
3835
"@types/node": "^14.14.21",
3936
"ava": "^3.15.0",

src/index.ts

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,46 @@
11
import {EventEmitter} from 'events';
22
import {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');
66
import myDebug = require('debug');
77

88
const 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
}

tests/index.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const test = require('ava');
22
const TextFileDiff = require('../dist/index.js').default;
33

4-
test('test with header', t => {
4+
test('test with header', async t => {
55
const m = new TextFileDiff();
66
const expected = '+Additional\n+Another\n+Lines\n-Some\n-Simple\n+With\n';
77

@@ -13,11 +13,11 @@ test('test with header', t => {
1313
m.on('+', line => {
1414
actual += '+' + line + '\n';
1515
});
16-
m.diff('tests/file1.txt', 'tests/file2.txt');
16+
await m.diff('tests/file1.txt', 'tests/file2.txt');
1717
t.is(actual, expected);
1818
});
1919

20-
test('test skip header', t => {
20+
test('test skip header', async t => {
2121
const expected = '+Another\n+File\n+Lines\n-Some\n-Simple\n+With\n';
2222

2323
const m = new TextFileDiff({
@@ -31,6 +31,6 @@ test('test skip header', t => {
3131
m.on('+', line => {
3232
actual += '+' + line + '\n';
3333
});
34-
m.diff('tests/file1.txt', 'tests/file2.txt');
34+
await m.diff('tests/file1.txt', 'tests/file2.txt');
3535
t.is(actual, expected);
3636
});

tsconfig.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,5 @@
5454
},
5555
"include": [
5656
"src/**/*.ts"
57-
],
58-
"types": [
59-
"n-readlines"
6057
]
6158
}

0 commit comments

Comments
 (0)