-
Notifications
You must be signed in to change notification settings - Fork 218
Expand file tree
/
Copy pathcsv.js
More file actions
84 lines (70 loc) · 2.07 KB
/
csv.js
File metadata and controls
84 lines (70 loc) · 2.07 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
/**
* An Example of implementing a CSV Grammar with Chevrotain.
*
* Based on: https://github.com/antlr/grammars-v4/blob/master/csv/CSV.g4
*
* Note that this is a pure grammar without any actions (either embedded or via a CST Visitor).
*/
import { createToken, Lexer, CstParser, EMPTY_ALT } from "chevrotain";
// ----------------- lexer -----------------
const Text = createToken({ name: "Text", pattern: /[^,\n\r"]+/ });
const Comma = createToken({ name: "Comma", pattern: /,/ });
const NewLine = createToken({
name: "NewLine",
pattern: /\r?\n/,
});
const String = createToken({ name: "String", pattern: /"(?:""|[^"])*"/ });
const allTokens = [Text, String, Comma, NewLine];
const CsvLexer = new Lexer(allTokens);
// Parser
class CsvParser extends CstParser {
constructor() {
super(allTokens);
// not mandatory, using $ (or any other sign) to reduce verbosity
const $ = this;
$.RULE("csvFile", () => {
$.SUBRULE($.hdr);
$.AT_LEAST_ONE(() => {
$.SUBRULE2($.row);
});
});
$.RULE("hdr", () => {
$.SUBRULE($.row);
});
$.RULE("row", () => {
$.SUBRULE($.field);
$.MANY(() => {
$.CONSUME(Comma);
$.SUBRULE2($.field);
});
$.CONSUME(NewLine);
});
$.RULE("field", () => {
$.OR([
{ ALT: () => $.CONSUME(Text) },
{ ALT: () => $.CONSUME(String) },
{ ALT: EMPTY_ALT("empty field") },
]);
});
// very important to call this after all the rules have been defined.
// otherwise the parser may not work correctly as it will lack information
// derived during the self analysis phase.
this.performSelfAnalysis();
}
}
// wrapping it all together
// reuse the same parser instance.
const parser = new CsvParser([]);
export function parseCsv(text) {
// 1. Tokenize the input.
const lexResult = CsvLexer.tokenize(text);
// 2. Set the Parser's input
parser.input = lexResult.tokens;
// 3. invoke the desired parser rule
const cst = parser.csvFile();
return {
cst: cst,
lexResult: lexResult,
parseErrors: parser.errors,
};
}