-
Notifications
You must be signed in to change notification settings - Fork 66
Expand file tree
/
Copy pathparser.js
More file actions
116 lines (90 loc) · 3.43 KB
/
parser.js
File metadata and controls
116 lines (90 loc) · 3.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import fs from 'fs';
import { EventEmitter } from 'events';
import Header from './header';
export default class Parser extends EventEmitter {
constructor(filename, options) {
super();
this.filename = filename;
this.options = options || {};
this.encoding = this.options.encoding || 'utf-8';
}
parse() {
this.emit('start', this);
this.header = new Header(this.filename, this.encoding);
this.header.parse(err => {
this.emit('header', this.header);
let sequenceNumber = 0;
let loc = this.header.start;
let bufLoc = this.header.start;
let overflow = null;
this.paused = false;
const stream = fs.createReadStream(this.filename);
this.readBuf = () => {
let buffer;
if (this.paused) {
this.emit('paused');
return;
}
while ((buffer = stream.read())) {
if (bufLoc !== this.header.start) { bufLoc = 0; }
if (overflow !== null) { buffer = overflow + buffer; }
while ((loc < (this.header.start + (this.header.numberOfRecords * this.header.recordLength))) && ((bufLoc + this.header.recordLength) <= buffer.length)) {
this.emit('record', this.parseRecord(++sequenceNumber, buffer.slice(bufLoc, (bufLoc += this.header.recordLength))));
}
loc += bufLoc;
if (bufLoc < buffer.length) { overflow = buffer.slice(bufLoc, buffer.length); } else { overflow = null; }
return this;
}
};
stream.on('readable',this.readBuf);
return stream.on('end', () => {
return this.emit('end');
});
});
return this;
}
pause() {
return this.paused = true;
}
resume() {
this.paused = false;
this.emit('resuming');
return (this.readBuf)();
}
parseRecord(sequenceNumber, buffer) {
const record = {
'@sequenceNumber': sequenceNumber,
'@deleted': [42,'*'].includes((buffer.slice(0, 1))[0])
};
let loc = 1;
for (let field of Array.from(this.header.fields)) {
(field => {
return record[field.name] = this.parseField(field, buffer.slice(loc, (loc += field.length)));
})(field);
}
return record;
}
parseField(field, buffer) {
let value = (buffer.toString(this.encoding)).trim();
if (field.type === 'C') { // Character
value = value;
} else if (field.type === 'F') { // Floating Point
value = (value === +value) && (value === (value | 0)) ? parseInt(value, 10) : parseFloat(value, 10);
} else if (field.type == 'L') { // Logical
if (['Y', 'y', 'T', 't'].includes(value)) {
value = true;
}
else if (['N', 'n', 'F', 'f'].includes(value)) {
value = false;
}
else {
value = null;
}
} else if (field.type === 'M') { // Memo
value = value;
} else if (field.type === 'N') { // Numeric
value = value === +value && value === (value|0) ? parseInt(value) : parseFloat(value, 10);
}
return value;
}
}