1 | const debug = require("debug")("streamroller:fileNameParser");
|
---|
2 | const FILENAME_SEP = ".";
|
---|
3 | const ZIP_EXT = ".gz";
|
---|
4 | const format = require("date-format");
|
---|
5 |
|
---|
6 | module.exports = ({ file, keepFileExt, pattern }) => {
|
---|
7 | // All these functions take two arguments: f, the filename, and p, the result placeholder
|
---|
8 | // They return the filename with any matching parts removed.
|
---|
9 | // The "zip" function, for instance, removes the ".gz" part of the filename (if present)
|
---|
10 | const zip = (f, p) => {
|
---|
11 | if (f.endsWith(ZIP_EXT)) {
|
---|
12 | debug("it is gzipped");
|
---|
13 | p.isCompressed = true;
|
---|
14 | return f.slice(0, -1 * ZIP_EXT.length);
|
---|
15 | }
|
---|
16 | return f;
|
---|
17 | };
|
---|
18 |
|
---|
19 | const __NOT_MATCHING__ = "__NOT_MATCHING__";
|
---|
20 |
|
---|
21 | const extAtEnd = f => {
|
---|
22 | if (f.startsWith(file.name) && f.endsWith(file.ext)) {
|
---|
23 | debug("it starts and ends with the right things");
|
---|
24 | return f.slice(file.name.length + 1, -1 * file.ext.length);
|
---|
25 | }
|
---|
26 | return __NOT_MATCHING__;
|
---|
27 | };
|
---|
28 |
|
---|
29 | const extInMiddle = f => {
|
---|
30 | if (f.startsWith(file.base)) {
|
---|
31 | debug("it starts with the right things");
|
---|
32 | return f.slice(file.base.length + 1);
|
---|
33 | }
|
---|
34 | return __NOT_MATCHING__;
|
---|
35 | };
|
---|
36 |
|
---|
37 | const dateAndIndex = (f, p) => {
|
---|
38 | const items = f.split(FILENAME_SEP);
|
---|
39 | let indexStr = items[items.length - 1];
|
---|
40 | debug("items: ", items, ", indexStr: ", indexStr);
|
---|
41 | let dateStr = f;
|
---|
42 | if (indexStr !== undefined && indexStr.match(/^\d+$/)) {
|
---|
43 | dateStr = f.slice(0, -1 * (indexStr.length + 1));
|
---|
44 | debug(`dateStr is ${dateStr}`);
|
---|
45 | if (pattern && !dateStr) {
|
---|
46 | dateStr = indexStr;
|
---|
47 | indexStr = "0";
|
---|
48 | }
|
---|
49 | } else {
|
---|
50 | indexStr = "0";
|
---|
51 | }
|
---|
52 |
|
---|
53 | try {
|
---|
54 | // Two arguments for new Date() are intentional. This will set other date
|
---|
55 | // components to minimal values in the current timezone instead of UTC,
|
---|
56 | // as new Date(0) will do.
|
---|
57 | const date = format.parse(pattern, dateStr, new Date(0, 0));
|
---|
58 | if (format.asString(pattern, date) !== dateStr) return f;
|
---|
59 | p.index = parseInt(indexStr, 10);
|
---|
60 | p.date = dateStr;
|
---|
61 | p.timestamp = date.getTime();
|
---|
62 | return "";
|
---|
63 | } catch (e) {
|
---|
64 | //not a valid date, don't panic.
|
---|
65 | debug(`Problem parsing ${dateStr} as ${pattern}, error was: `, e);
|
---|
66 | return f;
|
---|
67 | }
|
---|
68 | };
|
---|
69 |
|
---|
70 | const index = (f, p) => {
|
---|
71 | if (f.match(/^\d+$/)) {
|
---|
72 | debug("it has an index");
|
---|
73 | p.index = parseInt(f, 10);
|
---|
74 | return "";
|
---|
75 | }
|
---|
76 | return f;
|
---|
77 | };
|
---|
78 |
|
---|
79 | let parts = [
|
---|
80 | zip,
|
---|
81 | keepFileExt ? extAtEnd : extInMiddle,
|
---|
82 | pattern ? dateAndIndex : index
|
---|
83 | ];
|
---|
84 |
|
---|
85 | return filename => {
|
---|
86 | let result = { filename, index: 0, isCompressed: false };
|
---|
87 | // pass the filename through each of the file part parsers
|
---|
88 | let whatsLeftOver = parts.reduce(
|
---|
89 | (remains, part) => part(remains, result),
|
---|
90 | filename
|
---|
91 | );
|
---|
92 | // if there's anything left after parsing, then it wasn't a valid filename
|
---|
93 | return whatsLeftOver ? null : result;
|
---|
94 | };
|
---|
95 | };
|
---|