[6a3a178] | 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 | };
|
---|