@utilarium/dreadcabinet 0.0.16-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.nvmrc +2 -0
- package/LICENSE +190 -0
- package/README.md +95 -0
- package/dist/configure.d.ts +5 -0
- package/dist/configure.js +44 -0
- package/dist/configure.js.map +1 -0
- package/dist/constants.d.ts +36 -0
- package/dist/constants.js +53 -0
- package/dist/constants.js.map +1 -0
- package/dist/defaults.d.ts +2 -0
- package/dist/defaults.js +32 -0
- package/dist/defaults.js.map +1 -0
- package/dist/dreadcabinet.cjs +1793 -0
- package/dist/dreadcabinet.cjs.map +1 -0
- package/dist/dreadcabinet.d.ts +131 -0
- package/dist/dreadcabinet.js +111 -0
- package/dist/dreadcabinet.js.map +1 -0
- package/dist/error/ArgumentError.d.ts +5 -0
- package/dist/error/ArgumentError.js +26 -0
- package/dist/error/ArgumentError.js.map +1 -0
- package/dist/input/input.d.ts +7 -0
- package/dist/input/input.js +13 -0
- package/dist/input/input.js.map +1 -0
- package/dist/input/process.d.ts +5 -0
- package/dist/input/process.js +36 -0
- package/dist/input/process.js.map +1 -0
- package/dist/input/structured.d.ts +15 -0
- package/dist/input/structured.js +324 -0
- package/dist/input/structured.js.map +1 -0
- package/dist/input/unstructured.d.ts +2 -0
- package/dist/input/unstructured.js +45 -0
- package/dist/input/unstructured.js.map +1 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.js +19 -0
- package/dist/logger.js.map +1 -0
- package/dist/operate.d.ts +2 -0
- package/dist/operate.js +27 -0
- package/dist/operate.js.map +1 -0
- package/dist/output.d.ts +7 -0
- package/dist/output.js +99 -0
- package/dist/output.js.map +1 -0
- package/dist/read.d.ts +4 -0
- package/dist/read.js +30 -0
- package/dist/read.js.map +1 -0
- package/dist/util/dates.d.ts +60 -0
- package/dist/util/dates.js +699 -0
- package/dist/util/dates.js.map +1 -0
- package/dist/util/storage.d.ts +33 -0
- package/dist/util/storage.js +140 -0
- package/dist/util/storage.js.map +1 -0
- package/dist/validate.d.ts +4 -0
- package/dist/validate.js +134 -0
- package/dist/validate.js.map +1 -0
- package/guide/architecture.md +60 -0
- package/guide/configuration.md +132 -0
- package/guide/development.md +110 -0
- package/guide/index.md +62 -0
- package/guide/usage.md +166 -0
- package/output/kodrdriv/250703-0645-commit-message.md +21 -0
- package/output/kodrdriv/250703-0653-commit-message.md +1 -0
- package/output/kodrdriv/250703-0654-commit-message.md +1 -0
- package/output/kodrdriv/250703-0655-release-notes.md +51 -0
- package/output/kodrdriv/250703-0700-commit-message.md +1 -0
- package/output/kodrdriv/250703-0700-release-notes.md +8 -0
- package/output/kodrdriv/250703-0706-commit-message.md +1 -0
- package/output/kodrdriv/250703-0706-release-notes.md +11 -0
- package/output/kodrdriv/250703-0717-commit-message.md +1 -0
- package/output/kodrdriv/250703-0719-commit-message.md +1 -0
- package/output/kodrdriv/250703-0719-release-notes.md +17 -0
- package/output/kodrdriv/250703-0730-commit-message.md +1 -0
- package/output/kodrdriv/250703-0730-release-notes.md +11 -0
- package/output/kodrdriv/250703-1510-commit-message.md +1 -0
- package/output/kodrdriv/250710-0805-commit-message.md +3 -0
- package/output/kodrdriv/250710-0815-commit-message.md +1 -0
- package/output/kodrdriv/250710-0815-release-notes.md +39 -0
- package/output/kodrdriv/260107-2021-commit-message.md +37 -0
- package/output/kodrdriv/260108-0432-commit-message.md +6 -0
- package/output/kodrdriv/260108-0435-commit-message.md +3 -0
- package/output/kodrdriv/260108-0436-commit-message.md +4 -0
- package/output/kodrdriv/260108-0439-release-notes.md +63 -0
- package/output/kodrdriv/260108-0543-commit-message.md +19 -0
- package/output/kodrdriv/260108-0550-commit-message.md +3 -0
- package/output/kodrdriv/260108-0550-release-notes.md +19 -0
- package/output/kodrdriv/260108-0600-commit-message.md +3 -0
- package/output/kodrdriv/260110-0717-commit-message.md +4 -0
- package/output/kodrdriv/260110-1152-commit-message.md +1 -0
- package/output/kodrdriv/260110-1850-commit-message.md +1 -0
- package/output/kodrdriv/260110-1852-release-notes.md +33 -0
- package/output/kodrdriv/260112-2257-commit-message.md +5 -0
- package/output/kodrdriv/260112-2317-commit-message.md +1 -0
- package/output/kodrdriv/260112-2318-release-notes.md +42 -0
- package/output/kodrdriv/260113-0053-commit-message.md +1 -0
- package/output/kodrdriv/260113-0054-commit-message.md +1 -0
- package/output/kodrdriv/260113-0054-release-notes.md +49 -0
- package/output/kodrdriv/260130-1132-commit-message.md +1 -0
- package/output/kodrdriv/260130-1135-commit-message.md +1 -0
- package/output/kodrdriv/260130-1335-commit-message.md +10 -0
- package/output/kodrdriv/RELEASE_NOTES.md +47 -0
- package/output/kodrdriv/RELEASE_TITLE.md +1 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-08T04-21-54-623Z.md +372 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-08T12-32-36-513Z.md +55 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-08T12-35-58-580Z.md +105 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-08T12-36-05-658Z.md +53 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-08T13-43-55-498Z.md +178 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-08T13-50-10-230Z.md +53 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-08T13-50-35-136Z.md +52 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-08T14-00-30-772Z.md +52 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-10T15-17-43-324Z.md +53 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-10T19-52-47-424Z.md +97 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-11T02-50-23-123Z.md +138 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-11T02-50-45-038Z.md +114 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-11T02-50-49-467Z.md +114 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-13T06-57-00-384Z.md +169 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-13T07-17-29-292Z.md +114 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-13T07-17-47-579Z.md +114 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-13T08-48-55-599Z.md +144 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-13T08-53-53-725Z.md +114 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-13T08-54-11-600Z.md +97 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-30T19-32-17-053Z.md +174 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-30T19-35-00-887Z.md +152 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-30T21-02-16-553Z.md +236 -0
- package/output/kodrdriv/agentic-reflection-commit-2026-01-30T21-17-22-227Z.md +347 -0
- package/output/kodrdriv/agentic-reflection-release-2026-01-08T12-39-08-279Z.md +507 -0
- package/output/kodrdriv/agentic-reflection-release-2026-01-08T13-50-57-683Z.md +183 -0
- package/output/kodrdriv/agentic-reflection-release-2026-01-11T02-52-39-082Z.md +347 -0
- package/output/kodrdriv/agentic-reflection-release-2026-01-13T07-18-21-218Z.md +315 -0
- package/output/kodrdriv/agentic-reflection-release-2026-01-13T08-54-59-340Z.md +354 -0
- package/package.json +80 -0
|
@@ -0,0 +1,1793 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
|
|
5
|
+
const dayjs = require('dayjs');
|
|
6
|
+
const timezone = require('dayjs/plugin/timezone.js');
|
|
7
|
+
const utc = require('dayjs/plugin/utc.js');
|
|
8
|
+
const fs = require('node:fs');
|
|
9
|
+
const glob = require('glob');
|
|
10
|
+
const path = require('node:path');
|
|
11
|
+
const crypto = require('node:crypto');
|
|
12
|
+
const zod = require('zod');
|
|
13
|
+
|
|
14
|
+
function _interopNamespaceDefault(e) {
|
|
15
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
|
|
16
|
+
if (e) {
|
|
17
|
+
for (const k in e) {
|
|
18
|
+
if (k !== 'default') {
|
|
19
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
20
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: () => e[k]
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
n.default = e;
|
|
28
|
+
return Object.freeze(n);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
|
|
32
|
+
const path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
|
|
33
|
+
const crypto__namespace = /*#__PURE__*/_interopNamespaceDefault(crypto);
|
|
34
|
+
|
|
35
|
+
const PROGRAM_NAME = 'dreadcabinet';
|
|
36
|
+
const DEFAULT_TIMEZONE = 'Etc/UTC';
|
|
37
|
+
const DATE_FORMAT_MONTH_DAY = 'M-D';
|
|
38
|
+
const DATE_FORMAT_YEAR = 'YYYY';
|
|
39
|
+
const DATE_FORMAT_YEAR_MONTH_DAY = 'YYYY-M-D';
|
|
40
|
+
const DATE_FORMAT_MONTH = 'M';
|
|
41
|
+
const DATE_FORMAT_DAY = 'D';
|
|
42
|
+
const DEFAULT_RECURSIVE = false;
|
|
43
|
+
const DEFAULT_INPUT_DIRECTORY = './';
|
|
44
|
+
const DEFAULT_OUTPUT_DIRECTORY = './';
|
|
45
|
+
const DEFAULT_CONCURRENCY = 1;
|
|
46
|
+
const DEFAULT_OUTPUT_STRUCTURE = 'month';
|
|
47
|
+
const DEFAULT_OUTPUT_FILENAME_OPTIONS = [
|
|
48
|
+
'date',
|
|
49
|
+
'subject'
|
|
50
|
+
];
|
|
51
|
+
const DEFAULT_INPUT_STRUCTURE = 'month';
|
|
52
|
+
const DEFAULT_INPUT_FILENAME_OPTIONS = [
|
|
53
|
+
'date',
|
|
54
|
+
'subject'
|
|
55
|
+
];
|
|
56
|
+
const DEFAULT_EXTENSIONS = [
|
|
57
|
+
'md'
|
|
58
|
+
];
|
|
59
|
+
const ALLOWED_INPUT_STRUCTURES = [
|
|
60
|
+
'none',
|
|
61
|
+
'year',
|
|
62
|
+
'month',
|
|
63
|
+
'day'
|
|
64
|
+
];
|
|
65
|
+
const ALLOWED_INPUT_FILENAME_OPTIONS = [
|
|
66
|
+
'date',
|
|
67
|
+
'time',
|
|
68
|
+
'subject'
|
|
69
|
+
];
|
|
70
|
+
const ALLOWED_OUTPUT_STRUCTURES = [
|
|
71
|
+
'none',
|
|
72
|
+
'year',
|
|
73
|
+
'month',
|
|
74
|
+
'day'
|
|
75
|
+
];
|
|
76
|
+
const ALLOWED_OUTPUT_FILENAME_OPTIONS = [
|
|
77
|
+
'date',
|
|
78
|
+
'time',
|
|
79
|
+
'subject'
|
|
80
|
+
];
|
|
81
|
+
const ALLOWED_EXTENSIONS = [
|
|
82
|
+
'md',
|
|
83
|
+
'txt'
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
function _define_property(obj, key, value) {
|
|
87
|
+
if (key in obj) {
|
|
88
|
+
Object.defineProperty(obj, key, {
|
|
89
|
+
value: value,
|
|
90
|
+
enumerable: true,
|
|
91
|
+
configurable: true,
|
|
92
|
+
writable: true
|
|
93
|
+
});
|
|
94
|
+
} else {
|
|
95
|
+
obj[key] = value;
|
|
96
|
+
}
|
|
97
|
+
return obj;
|
|
98
|
+
}
|
|
99
|
+
class ArgumentError extends Error {
|
|
100
|
+
get argument() {
|
|
101
|
+
return this.argumentName;
|
|
102
|
+
}
|
|
103
|
+
constructor(argumentName, message){
|
|
104
|
+
super(`${message}`), _define_property(this, "argumentName", void 0);
|
|
105
|
+
this.name = 'ArgumentError';
|
|
106
|
+
this.argumentName = argumentName;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const addOption = (command, option, description, addDefaults, defaultValue)=>{
|
|
111
|
+
if (addDefaults) {
|
|
112
|
+
command.option(option, description, defaultValue);
|
|
113
|
+
} else {
|
|
114
|
+
const defaultDesc = defaultValue === undefined ? 'undefined' : Array.isArray(defaultValue) ? defaultValue.join(',') : defaultValue;
|
|
115
|
+
const descriptionWithDefaults = `${description} (default: ${defaultDesc})`;
|
|
116
|
+
command.option(option, descriptionWithDefaults);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
const configure = async (command, defaults, addDefaults, features)=>{
|
|
120
|
+
const tzDefault = (defaults === null || defaults === void 0 ? void 0 : defaults.timezone) || DEFAULT_TIMEZONE;
|
|
121
|
+
if (addDefaults) {
|
|
122
|
+
command.option('--timezone <timezone>', 'timezone for date calculations', tzDefault);
|
|
123
|
+
} else {
|
|
124
|
+
command.option('--timezone <timezone>', `timezone for date calculations (default: ${tzDefault})`);
|
|
125
|
+
}
|
|
126
|
+
if (features.includes('input')) {
|
|
127
|
+
addOption(command, '-r, --recursive', 'recursive mode, process all files in the input directory', addDefaults, (defaults === null || defaults === void 0 ? void 0 : defaults.recursive) !== undefined ? defaults.recursive : DEFAULT_RECURSIVE);
|
|
128
|
+
addOption(command, '-i, --input-directory <inputDirectory>', 'input directory', addDefaults, (defaults === null || defaults === void 0 ? void 0 : defaults.inputDirectory) || DEFAULT_INPUT_DIRECTORY);
|
|
129
|
+
addOption(command, '--limit <limit>', 'limit the number of files to process', addDefaults, (defaults === null || defaults === void 0 ? void 0 : defaults.limit) ? defaults === null || defaults === void 0 ? void 0 : defaults.limit.toString() : undefined);
|
|
130
|
+
addOption(command, '--concurrency <concurrency>', 'concurrency level for processing files', addDefaults, (defaults === null || defaults === void 0 ? void 0 : defaults.concurrency) ? defaults === null || defaults === void 0 ? void 0 : defaults.concurrency.toString() : undefined);
|
|
131
|
+
}
|
|
132
|
+
if (features.includes('output')) {
|
|
133
|
+
addOption(command, '-o, --output-directory <outputDirectory>', 'output directory', addDefaults, (defaults === null || defaults === void 0 ? void 0 : defaults.outputDirectory) || DEFAULT_OUTPUT_DIRECTORY);
|
|
134
|
+
}
|
|
135
|
+
if (features.includes('structured-output')) {
|
|
136
|
+
addOption(command, '--output-structure <type>', 'output directory structure (none/year/month/day)', addDefaults, (defaults === null || defaults === void 0 ? void 0 : defaults.outputStructure) || DEFAULT_OUTPUT_STRUCTURE);
|
|
137
|
+
addOption(command, '--output-filename-options [outputFilenameOptions...]', 'filename format options (space-separated list of: date,time,subject) example \'date subject\'', addDefaults, (defaults === null || defaults === void 0 ? void 0 : defaults.outputFilenameOptions) || DEFAULT_OUTPUT_FILENAME_OPTIONS);
|
|
138
|
+
}
|
|
139
|
+
if (features.includes('extensions')) {
|
|
140
|
+
addOption(command, '--extensions [extensions...]', 'file extensions to process (space-separated list of: mp3,mp4,mpeg,mpga,m4a,wav,webm)', addDefaults, (defaults === null || defaults === void 0 ? void 0 : defaults.extensions) || DEFAULT_EXTENSIONS);
|
|
141
|
+
}
|
|
142
|
+
if (features.includes('structured-input')) {
|
|
143
|
+
addOption(command, '--input-structure <type>', 'input directory structure (none/year/month/day)', addDefaults, (defaults === null || defaults === void 0 ? void 0 : defaults.inputStructure) || DEFAULT_INPUT_STRUCTURE);
|
|
144
|
+
addOption(command, '--input-filename-options [options...]', 'filename format options (space-separated list of: date,time,subject)', addDefaults, (defaults === null || defaults === void 0 ? void 0 : defaults.inputFilenameOptions) || DEFAULT_INPUT_FILENAME_OPTIONS);
|
|
145
|
+
addOption(command, '--start <date>', `start date filter (${DATE_FORMAT_YEAR_MONTH_DAY})`, addDefaults, undefined);
|
|
146
|
+
addOption(command, '--end <date>', `end date filter (${DATE_FORMAT_YEAR_MONTH_DAY}), defaults to today`, addDefaults, undefined);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const applyDefaults = (config, features, defaults)=>{
|
|
151
|
+
const configWithDefaults = {
|
|
152
|
+
...config
|
|
153
|
+
};
|
|
154
|
+
configWithDefaults.timezone = config.timezone || (defaults === null || defaults === void 0 ? void 0 : defaults.timezone) || DEFAULT_TIMEZONE;
|
|
155
|
+
if (features.includes('input')) {
|
|
156
|
+
var _ref;
|
|
157
|
+
configWithDefaults.recursive = config.recursive === undefined ? (_ref = defaults === null || defaults === void 0 ? void 0 : defaults.recursive) !== null && _ref !== void 0 ? _ref : DEFAULT_RECURSIVE : config.recursive;
|
|
158
|
+
configWithDefaults.inputDirectory = config.inputDirectory || (defaults === null || defaults === void 0 ? void 0 : defaults.inputDirectory) || DEFAULT_INPUT_DIRECTORY;
|
|
159
|
+
configWithDefaults.concurrency = config.concurrency || (defaults === null || defaults === void 0 ? void 0 : defaults.concurrency) || DEFAULT_CONCURRENCY;
|
|
160
|
+
}
|
|
161
|
+
if (features.includes('output')) {
|
|
162
|
+
configWithDefaults.outputDirectory = config.outputDirectory || (defaults === null || defaults === void 0 ? void 0 : defaults.outputDirectory) || DEFAULT_OUTPUT_DIRECTORY;
|
|
163
|
+
}
|
|
164
|
+
if (features.includes('structured-output')) {
|
|
165
|
+
configWithDefaults.outputStructure = config.outputStructure || (defaults === null || defaults === void 0 ? void 0 : defaults.outputStructure) || DEFAULT_OUTPUT_STRUCTURE;
|
|
166
|
+
configWithDefaults.outputFilenameOptions = config.outputFilenameOptions || (defaults === null || defaults === void 0 ? void 0 : defaults.outputFilenameOptions) || DEFAULT_OUTPUT_FILENAME_OPTIONS;
|
|
167
|
+
}
|
|
168
|
+
if (features.includes('extensions')) {
|
|
169
|
+
configWithDefaults.extensions = config.extensions || (defaults === null || defaults === void 0 ? void 0 : defaults.extensions) || DEFAULT_EXTENSIONS;
|
|
170
|
+
}
|
|
171
|
+
if (features.includes('structured-input')) {
|
|
172
|
+
configWithDefaults.inputStructure = config.inputStructure || (defaults === null || defaults === void 0 ? void 0 : defaults.inputStructure) || DEFAULT_INPUT_STRUCTURE;
|
|
173
|
+
configWithDefaults.inputFilenameOptions = config.inputFilenameOptions || (defaults === null || defaults === void 0 ? void 0 : defaults.inputFilenameOptions) || DEFAULT_INPUT_FILENAME_OPTIONS;
|
|
174
|
+
}
|
|
175
|
+
return configWithDefaults;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
function clean(obj) {
|
|
179
|
+
return Object.fromEntries(Object.entries(obj).filter(([_, v])=>v !== undefined));
|
|
180
|
+
}
|
|
181
|
+
const read = async (args, features)=>{
|
|
182
|
+
const config = {};
|
|
183
|
+
config.timezone = args.timezone;
|
|
184
|
+
if (features.includes('input')) {
|
|
185
|
+
config.inputDirectory = args.inputDirectory;
|
|
186
|
+
config.limit = args.limit;
|
|
187
|
+
}
|
|
188
|
+
if (features.includes('structured-input')) {
|
|
189
|
+
config.inputStructure = args.inputStructure;
|
|
190
|
+
config.inputFilenameOptions = args.inputFilenameOptions;
|
|
191
|
+
}
|
|
192
|
+
if (features.includes('output')) {
|
|
193
|
+
config.outputDirectory = args.outputDirectory;
|
|
194
|
+
}
|
|
195
|
+
if (features.includes('structured-output')) {
|
|
196
|
+
config.outputStructure = args.outputStructure;
|
|
197
|
+
config.outputFilenameOptions = args.outputFilenameOptions;
|
|
198
|
+
}
|
|
199
|
+
if (features.includes('extensions')) {
|
|
200
|
+
config.extensions = args.extensions;
|
|
201
|
+
}
|
|
202
|
+
// Returning a clean object to avoid undefined values
|
|
203
|
+
return clean(config);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// eslint-disable-next-line no-restricted-imports
|
|
207
|
+
dayjs.extend(utc);
|
|
208
|
+
dayjs.extend(timezone);
|
|
209
|
+
// Static list of IANA timezone names (replaces moment-timezone dependency)
|
|
210
|
+
const TIMEZONE_NAMES = [
|
|
211
|
+
'Africa/Abidjan',
|
|
212
|
+
'Africa/Accra',
|
|
213
|
+
'Africa/Addis_Ababa',
|
|
214
|
+
'Africa/Algiers',
|
|
215
|
+
'Africa/Asmara',
|
|
216
|
+
'Africa/Asmera',
|
|
217
|
+
'Africa/Bamako',
|
|
218
|
+
'Africa/Bangui',
|
|
219
|
+
'Africa/Banjul',
|
|
220
|
+
'Africa/Bissau',
|
|
221
|
+
'Africa/Blantyre',
|
|
222
|
+
'Africa/Brazzaville',
|
|
223
|
+
'Africa/Bujumbura',
|
|
224
|
+
'Africa/Cairo',
|
|
225
|
+
'Africa/Casablanca',
|
|
226
|
+
'Africa/Ceuta',
|
|
227
|
+
'Africa/Conakry',
|
|
228
|
+
'Africa/Dakar',
|
|
229
|
+
'Africa/Dar_es_Salaam',
|
|
230
|
+
'Africa/Djibouti',
|
|
231
|
+
'Africa/Douala',
|
|
232
|
+
'Africa/El_Aaiun',
|
|
233
|
+
'Africa/Freetown',
|
|
234
|
+
'Africa/Gaborone',
|
|
235
|
+
'Africa/Harare',
|
|
236
|
+
'Africa/Johannesburg',
|
|
237
|
+
'Africa/Juba',
|
|
238
|
+
'Africa/Kampala',
|
|
239
|
+
'Africa/Khartoum',
|
|
240
|
+
'Africa/Kigali',
|
|
241
|
+
'Africa/Kinshasa',
|
|
242
|
+
'Africa/Lagos',
|
|
243
|
+
'Africa/Libreville',
|
|
244
|
+
'Africa/Lome',
|
|
245
|
+
'Africa/Luanda',
|
|
246
|
+
'Africa/Lubumbashi',
|
|
247
|
+
'Africa/Lusaka',
|
|
248
|
+
'Africa/Malabo',
|
|
249
|
+
'Africa/Maputo',
|
|
250
|
+
'Africa/Maseru',
|
|
251
|
+
'Africa/Mbabane',
|
|
252
|
+
'Africa/Mogadishu',
|
|
253
|
+
'Africa/Monrovia',
|
|
254
|
+
'Africa/Nairobi',
|
|
255
|
+
'Africa/Ndjamena',
|
|
256
|
+
'Africa/Niamey',
|
|
257
|
+
'Africa/Nouakchott',
|
|
258
|
+
'Africa/Ouagadougou',
|
|
259
|
+
'Africa/Porto-Novo',
|
|
260
|
+
'Africa/Sao_Tome',
|
|
261
|
+
'Africa/Timbuktu',
|
|
262
|
+
'Africa/Tripoli',
|
|
263
|
+
'Africa/Tunis',
|
|
264
|
+
'Africa/Windhoek',
|
|
265
|
+
'America/Adak',
|
|
266
|
+
'America/Anchorage',
|
|
267
|
+
'America/Anguilla',
|
|
268
|
+
'America/Antigua',
|
|
269
|
+
'America/Araguaina',
|
|
270
|
+
'America/Argentina/Buenos_Aires',
|
|
271
|
+
'America/Argentina/Catamarca',
|
|
272
|
+
'America/Argentina/ComodRivadavia',
|
|
273
|
+
'America/Argentina/Cordoba',
|
|
274
|
+
'America/Argentina/Jujuy',
|
|
275
|
+
'America/Argentina/La_Rioja',
|
|
276
|
+
'America/Argentina/Mendoza',
|
|
277
|
+
'America/Argentina/Rio_Gallegos',
|
|
278
|
+
'America/Argentina/Salta',
|
|
279
|
+
'America/Argentina/San_Juan',
|
|
280
|
+
'America/Argentina/San_Luis',
|
|
281
|
+
'America/Argentina/Tucuman',
|
|
282
|
+
'America/Argentina/Ushuaia',
|
|
283
|
+
'America/Aruba',
|
|
284
|
+
'America/Asuncion',
|
|
285
|
+
'America/Atikokan',
|
|
286
|
+
'America/Atka',
|
|
287
|
+
'America/Bahia',
|
|
288
|
+
'America/Bahia_Banderas',
|
|
289
|
+
'America/Barbados',
|
|
290
|
+
'America/Belem',
|
|
291
|
+
'America/Belize',
|
|
292
|
+
'America/Blanc-Sablon',
|
|
293
|
+
'America/Boa_Vista',
|
|
294
|
+
'America/Bogota',
|
|
295
|
+
'America/Boise',
|
|
296
|
+
'America/Buenos_Aires',
|
|
297
|
+
'America/Cambridge_Bay',
|
|
298
|
+
'America/Campo_Grande',
|
|
299
|
+
'America/Cancun',
|
|
300
|
+
'America/Caracas',
|
|
301
|
+
'America/Catamarca',
|
|
302
|
+
'America/Cayenne',
|
|
303
|
+
'America/Cayman',
|
|
304
|
+
'America/Chicago',
|
|
305
|
+
'America/Chihuahua',
|
|
306
|
+
'America/Coral_Harbour',
|
|
307
|
+
'America/Cordoba',
|
|
308
|
+
'America/Costa_Rica',
|
|
309
|
+
'America/Creston',
|
|
310
|
+
'America/Cuiaba',
|
|
311
|
+
'America/Curacao',
|
|
312
|
+
'America/Danmarkshavn',
|
|
313
|
+
'America/Dawson',
|
|
314
|
+
'America/Dawson_Creek',
|
|
315
|
+
'America/Denver',
|
|
316
|
+
'America/Detroit',
|
|
317
|
+
'America/Dominica',
|
|
318
|
+
'America/Edmonton',
|
|
319
|
+
'America/Eirunepe',
|
|
320
|
+
'America/El_Salvador',
|
|
321
|
+
'America/Ensenada',
|
|
322
|
+
'America/Fort_Nelson',
|
|
323
|
+
'America/Fort_Wayne',
|
|
324
|
+
'America/Fortaleza',
|
|
325
|
+
'America/Glace_Bay',
|
|
326
|
+
'America/Godthab',
|
|
327
|
+
'America/Goose_Bay',
|
|
328
|
+
'America/Grand_Turk',
|
|
329
|
+
'America/Grenada',
|
|
330
|
+
'America/Guadeloupe',
|
|
331
|
+
'America/Guatemala',
|
|
332
|
+
'America/Guayaquil',
|
|
333
|
+
'America/Guyana',
|
|
334
|
+
'America/Halifax',
|
|
335
|
+
'America/Havana',
|
|
336
|
+
'America/Hermosillo',
|
|
337
|
+
'America/Indiana/Indianapolis',
|
|
338
|
+
'America/Indiana/Knox',
|
|
339
|
+
'America/Indiana/Marengo',
|
|
340
|
+
'America/Indiana/Petersburg',
|
|
341
|
+
'America/Indiana/Tell_City',
|
|
342
|
+
'America/Indiana/Vevay',
|
|
343
|
+
'America/Indiana/Vincennes',
|
|
344
|
+
'America/Indiana/Winamac',
|
|
345
|
+
'America/Indianapolis',
|
|
346
|
+
'America/Inuvik',
|
|
347
|
+
'America/Iqaluit',
|
|
348
|
+
'America/Jamaica',
|
|
349
|
+
'America/Jujuy',
|
|
350
|
+
'America/Juneau',
|
|
351
|
+
'America/Kentucky/Louisville',
|
|
352
|
+
'America/Kentucky/Monticello',
|
|
353
|
+
'America/Knox_IN',
|
|
354
|
+
'America/Kralendijk',
|
|
355
|
+
'America/La_Paz',
|
|
356
|
+
'America/Lima',
|
|
357
|
+
'America/Los_Angeles',
|
|
358
|
+
'America/Louisville',
|
|
359
|
+
'America/Lower_Princes',
|
|
360
|
+
'America/Maceio',
|
|
361
|
+
'America/Managua',
|
|
362
|
+
'America/Manaus',
|
|
363
|
+
'America/Marigot',
|
|
364
|
+
'America/Martinique',
|
|
365
|
+
'America/Matamoros',
|
|
366
|
+
'America/Mazatlan',
|
|
367
|
+
'America/Mendoza',
|
|
368
|
+
'America/Menominee',
|
|
369
|
+
'America/Merida',
|
|
370
|
+
'America/Metlakatla',
|
|
371
|
+
'America/Mexico_City',
|
|
372
|
+
'America/Miquelon',
|
|
373
|
+
'America/Moncton',
|
|
374
|
+
'America/Monterrey',
|
|
375
|
+
'America/Montevideo',
|
|
376
|
+
'America/Montreal',
|
|
377
|
+
'America/Montserrat',
|
|
378
|
+
'America/Nassau',
|
|
379
|
+
'America/New_York',
|
|
380
|
+
'America/Nipigon',
|
|
381
|
+
'America/Nome',
|
|
382
|
+
'America/Noronha',
|
|
383
|
+
'America/North_Dakota/Beulah',
|
|
384
|
+
'America/North_Dakota/Center',
|
|
385
|
+
'America/North_Dakota/New_Salem',
|
|
386
|
+
'America/Ojinaga',
|
|
387
|
+
'America/Panama',
|
|
388
|
+
'America/Pangnirtung',
|
|
389
|
+
'America/Paramaribo',
|
|
390
|
+
'America/Phoenix',
|
|
391
|
+
'America/Port-au-Prince',
|
|
392
|
+
'America/Port_of_Spain',
|
|
393
|
+
'America/Porto_Acre',
|
|
394
|
+
'America/Porto_Velho',
|
|
395
|
+
'America/Puerto_Rico',
|
|
396
|
+
'America/Punta_Arenas',
|
|
397
|
+
'America/Rainy_River',
|
|
398
|
+
'America/Rankin_Inlet',
|
|
399
|
+
'America/Recife',
|
|
400
|
+
'America/Regina',
|
|
401
|
+
'America/Resolute',
|
|
402
|
+
'America/Rio_Branco',
|
|
403
|
+
'America/Rosario',
|
|
404
|
+
'America/Santa_Isabel',
|
|
405
|
+
'America/Santarem',
|
|
406
|
+
'America/Santiago',
|
|
407
|
+
'America/Santo_Domingo',
|
|
408
|
+
'America/Sao_Paulo',
|
|
409
|
+
'America/Scoresbysund',
|
|
410
|
+
'America/Shiprock',
|
|
411
|
+
'America/Sitka',
|
|
412
|
+
'America/St_Barthelemy',
|
|
413
|
+
'America/St_Johns',
|
|
414
|
+
'America/St_Kitts',
|
|
415
|
+
'America/St_Lucia',
|
|
416
|
+
'America/St_Thomas',
|
|
417
|
+
'America/St_Vincent',
|
|
418
|
+
'America/Swift_Current',
|
|
419
|
+
'America/Tegucigalpa',
|
|
420
|
+
'America/Thule',
|
|
421
|
+
'America/Thunder_Bay',
|
|
422
|
+
'America/Tijuana',
|
|
423
|
+
'America/Toronto',
|
|
424
|
+
'America/Tortola',
|
|
425
|
+
'America/Vancouver',
|
|
426
|
+
'America/Virgin',
|
|
427
|
+
'America/Whitehorse',
|
|
428
|
+
'America/Winnipeg',
|
|
429
|
+
'America/Yakutat',
|
|
430
|
+
'America/Yellowknife',
|
|
431
|
+
'Antarctica/Casey',
|
|
432
|
+
'Antarctica/Davis',
|
|
433
|
+
'Antarctica/DumontDUrville',
|
|
434
|
+
'Antarctica/Macquarie',
|
|
435
|
+
'Antarctica/Mawson',
|
|
436
|
+
'Antarctica/McMurdo',
|
|
437
|
+
'Antarctica/Palmer',
|
|
438
|
+
'Antarctica/Rothera',
|
|
439
|
+
'Antarctica/South_Pole',
|
|
440
|
+
'Antarctica/Syowa',
|
|
441
|
+
'Antarctica/Troll',
|
|
442
|
+
'Antarctica/Vostok',
|
|
443
|
+
'Arctic/Longyearbyen',
|
|
444
|
+
'Asia/Aden',
|
|
445
|
+
'Asia/Almaty',
|
|
446
|
+
'Asia/Amman',
|
|
447
|
+
'Asia/Anadyr',
|
|
448
|
+
'Asia/Aqtau',
|
|
449
|
+
'Asia/Aqtobe',
|
|
450
|
+
'Asia/Ashgabat',
|
|
451
|
+
'Asia/Ashkhabad',
|
|
452
|
+
'Asia/Atyrau',
|
|
453
|
+
'Asia/Baghdad',
|
|
454
|
+
'Asia/Bahrain',
|
|
455
|
+
'Asia/Baku',
|
|
456
|
+
'Asia/Bangkok',
|
|
457
|
+
'Asia/Barnaul',
|
|
458
|
+
'Asia/Beirut',
|
|
459
|
+
'Asia/Bishkek',
|
|
460
|
+
'Asia/Brunei',
|
|
461
|
+
'Asia/Calcutta',
|
|
462
|
+
'Asia/Chita',
|
|
463
|
+
'Asia/Choibalsan',
|
|
464
|
+
'Asia/Chongqing',
|
|
465
|
+
'Asia/Chungking',
|
|
466
|
+
'Asia/Colombo',
|
|
467
|
+
'Asia/Dacca',
|
|
468
|
+
'Asia/Damascus',
|
|
469
|
+
'Asia/Dhaka',
|
|
470
|
+
'Asia/Dili',
|
|
471
|
+
'Asia/Dubai',
|
|
472
|
+
'Asia/Dushanbe',
|
|
473
|
+
'Asia/Famagusta',
|
|
474
|
+
'Asia/Gaza',
|
|
475
|
+
'Asia/Harbin',
|
|
476
|
+
'Asia/Hebron',
|
|
477
|
+
'Asia/Ho_Chi_Minh',
|
|
478
|
+
'Asia/Hong_Kong',
|
|
479
|
+
'Asia/Hovd',
|
|
480
|
+
'Asia/Irkutsk',
|
|
481
|
+
'Asia/Istanbul',
|
|
482
|
+
'Asia/Jakarta',
|
|
483
|
+
'Asia/Jayapura',
|
|
484
|
+
'Asia/Jerusalem',
|
|
485
|
+
'Asia/Kabul',
|
|
486
|
+
'Asia/Kamchatka',
|
|
487
|
+
'Asia/Karachi',
|
|
488
|
+
'Asia/Kashgar',
|
|
489
|
+
'Asia/Kathmandu',
|
|
490
|
+
'Asia/Katmandu',
|
|
491
|
+
'Asia/Khandyga',
|
|
492
|
+
'Asia/Kolkata',
|
|
493
|
+
'Asia/Krasnoyarsk',
|
|
494
|
+
'Asia/Kuala_Lumpur',
|
|
495
|
+
'Asia/Kuching',
|
|
496
|
+
'Asia/Kuwait',
|
|
497
|
+
'Asia/Macao',
|
|
498
|
+
'Asia/Macau',
|
|
499
|
+
'Asia/Magadan',
|
|
500
|
+
'Asia/Makassar',
|
|
501
|
+
'Asia/Manila',
|
|
502
|
+
'Asia/Muscat',
|
|
503
|
+
'Asia/Nicosia',
|
|
504
|
+
'Asia/Novokuznetsk',
|
|
505
|
+
'Asia/Novosibirsk',
|
|
506
|
+
'Asia/Omsk',
|
|
507
|
+
'Asia/Oral',
|
|
508
|
+
'Asia/Phnom_Penh',
|
|
509
|
+
'Asia/Pontianak',
|
|
510
|
+
'Asia/Pyongyang',
|
|
511
|
+
'Asia/Qatar',
|
|
512
|
+
'Asia/Qyzylorda',
|
|
513
|
+
'Asia/Rangoon',
|
|
514
|
+
'Asia/Riyadh',
|
|
515
|
+
'Asia/Saigon',
|
|
516
|
+
'Asia/Sakhalin',
|
|
517
|
+
'Asia/Samarkand',
|
|
518
|
+
'Asia/Seoul',
|
|
519
|
+
'Asia/Shanghai',
|
|
520
|
+
'Asia/Singapore',
|
|
521
|
+
'Asia/Srednekolymsk',
|
|
522
|
+
'Asia/Taipei',
|
|
523
|
+
'Asia/Tashkent',
|
|
524
|
+
'Asia/Tbilisi',
|
|
525
|
+
'Asia/Tehran',
|
|
526
|
+
'Asia/Tel_Aviv',
|
|
527
|
+
'Asia/Thimbu',
|
|
528
|
+
'Asia/Thimphu',
|
|
529
|
+
'Asia/Tokyo',
|
|
530
|
+
'Asia/Tomsk',
|
|
531
|
+
'Asia/Ujung_Pandang',
|
|
532
|
+
'Asia/Ulaanbaatar',
|
|
533
|
+
'Asia/Ulan_Bator',
|
|
534
|
+
'Asia/Urumqi',
|
|
535
|
+
'Asia/Ust-Nera',
|
|
536
|
+
'Asia/Vientiane',
|
|
537
|
+
'Asia/Vladivostok',
|
|
538
|
+
'Asia/Yakutsk',
|
|
539
|
+
'Asia/Yangon',
|
|
540
|
+
'Asia/Yekaterinburg',
|
|
541
|
+
'Asia/Yerevan',
|
|
542
|
+
'Atlantic/Azores',
|
|
543
|
+
'Atlantic/Bermuda',
|
|
544
|
+
'Atlantic/Canary',
|
|
545
|
+
'Atlantic/Cape_Verde',
|
|
546
|
+
'Atlantic/Faeroe',
|
|
547
|
+
'Atlantic/Faroe',
|
|
548
|
+
'Atlantic/Jan_Mayen',
|
|
549
|
+
'Atlantic/Madeira',
|
|
550
|
+
'Atlantic/Reykjavik',
|
|
551
|
+
'Atlantic/South_Georgia',
|
|
552
|
+
'Atlantic/St_Helena',
|
|
553
|
+
'Atlantic/Stanley',
|
|
554
|
+
'Australia/ACT',
|
|
555
|
+
'Australia/Adelaide',
|
|
556
|
+
'Australia/Brisbane',
|
|
557
|
+
'Australia/Broken_Hill',
|
|
558
|
+
'Australia/Canberra',
|
|
559
|
+
'Australia/Currie',
|
|
560
|
+
'Australia/Darwin',
|
|
561
|
+
'Australia/Eucla',
|
|
562
|
+
'Australia/Hobart',
|
|
563
|
+
'Australia/LHI',
|
|
564
|
+
'Australia/Lindeman',
|
|
565
|
+
'Australia/Lord_Howe',
|
|
566
|
+
'Australia/Melbourne',
|
|
567
|
+
'Australia/NSW',
|
|
568
|
+
'Australia/North',
|
|
569
|
+
'Australia/Perth',
|
|
570
|
+
'Australia/Queensland',
|
|
571
|
+
'Australia/South',
|
|
572
|
+
'Australia/Sydney',
|
|
573
|
+
'Australia/Tasmania',
|
|
574
|
+
'Australia/Victoria',
|
|
575
|
+
'Australia/West',
|
|
576
|
+
'Australia/Yancowinna',
|
|
577
|
+
'Brazil/Acre',
|
|
578
|
+
'Brazil/DeNoronha',
|
|
579
|
+
'Brazil/East',
|
|
580
|
+
'Brazil/West',
|
|
581
|
+
'CET',
|
|
582
|
+
'CST6CDT',
|
|
583
|
+
'Canada/Atlantic',
|
|
584
|
+
'Canada/Central',
|
|
585
|
+
'Canada/Eastern',
|
|
586
|
+
'Canada/Mountain',
|
|
587
|
+
'Canada/Newfoundland',
|
|
588
|
+
'Canada/Pacific',
|
|
589
|
+
'Canada/Saskatchewan',
|
|
590
|
+
'Canada/Yukon',
|
|
591
|
+
'Chile/Continental',
|
|
592
|
+
'Chile/EasterIsland',
|
|
593
|
+
'Cuba',
|
|
594
|
+
'EET',
|
|
595
|
+
'EST',
|
|
596
|
+
'EST5EDT',
|
|
597
|
+
'Egypt',
|
|
598
|
+
'Eire',
|
|
599
|
+
'Etc/GMT',
|
|
600
|
+
'Etc/GMT+0',
|
|
601
|
+
'Etc/GMT+1',
|
|
602
|
+
'Etc/GMT+10',
|
|
603
|
+
'Etc/GMT+11',
|
|
604
|
+
'Etc/GMT+12',
|
|
605
|
+
'Etc/GMT+2',
|
|
606
|
+
'Etc/GMT+3',
|
|
607
|
+
'Etc/GMT+4',
|
|
608
|
+
'Etc/GMT+5',
|
|
609
|
+
'Etc/GMT+6',
|
|
610
|
+
'Etc/GMT+7',
|
|
611
|
+
'Etc/GMT+8',
|
|
612
|
+
'Etc/GMT+9',
|
|
613
|
+
'Etc/GMT-0',
|
|
614
|
+
'Etc/GMT-1',
|
|
615
|
+
'Etc/GMT-10',
|
|
616
|
+
'Etc/GMT-11',
|
|
617
|
+
'Etc/GMT-12',
|
|
618
|
+
'Etc/GMT-13',
|
|
619
|
+
'Etc/GMT-14',
|
|
620
|
+
'Etc/GMT-2',
|
|
621
|
+
'Etc/GMT-3',
|
|
622
|
+
'Etc/GMT-4',
|
|
623
|
+
'Etc/GMT-5',
|
|
624
|
+
'Etc/GMT-6',
|
|
625
|
+
'Etc/GMT-7',
|
|
626
|
+
'Etc/GMT-8',
|
|
627
|
+
'Etc/GMT-9',
|
|
628
|
+
'Etc/GMT0',
|
|
629
|
+
'Etc/Greenwich',
|
|
630
|
+
'Etc/UCT',
|
|
631
|
+
'Etc/UTC',
|
|
632
|
+
'Etc/Universal',
|
|
633
|
+
'Etc/Zulu',
|
|
634
|
+
'Europe/Amsterdam',
|
|
635
|
+
'Europe/Andorra',
|
|
636
|
+
'Europe/Astrakhan',
|
|
637
|
+
'Europe/Athens',
|
|
638
|
+
'Europe/Belfast',
|
|
639
|
+
'Europe/Belgrade',
|
|
640
|
+
'Europe/Berlin',
|
|
641
|
+
'Europe/Bratislava',
|
|
642
|
+
'Europe/Brussels',
|
|
643
|
+
'Europe/Bucharest',
|
|
644
|
+
'Europe/Budapest',
|
|
645
|
+
'Europe/Busingen',
|
|
646
|
+
'Europe/Chisinau',
|
|
647
|
+
'Europe/Copenhagen',
|
|
648
|
+
'Europe/Dublin',
|
|
649
|
+
'Europe/Gibraltar',
|
|
650
|
+
'Europe/Guernsey',
|
|
651
|
+
'Europe/Helsinki',
|
|
652
|
+
'Europe/Isle_of_Man',
|
|
653
|
+
'Europe/Istanbul',
|
|
654
|
+
'Europe/Jersey',
|
|
655
|
+
'Europe/Kaliningrad',
|
|
656
|
+
'Europe/Kiev',
|
|
657
|
+
'Europe/Kirov',
|
|
658
|
+
'Europe/Lisbon',
|
|
659
|
+
'Europe/Ljubljana',
|
|
660
|
+
'Europe/London',
|
|
661
|
+
'Europe/Luxembourg',
|
|
662
|
+
'Europe/Madrid',
|
|
663
|
+
'Europe/Malta',
|
|
664
|
+
'Europe/Mariehamn',
|
|
665
|
+
'Europe/Minsk',
|
|
666
|
+
'Europe/Monaco',
|
|
667
|
+
'Europe/Moscow',
|
|
668
|
+
'Europe/Nicosia',
|
|
669
|
+
'Europe/Oslo',
|
|
670
|
+
'Europe/Paris',
|
|
671
|
+
'Europe/Podgorica',
|
|
672
|
+
'Europe/Prague',
|
|
673
|
+
'Europe/Riga',
|
|
674
|
+
'Europe/Rome',
|
|
675
|
+
'Europe/Samara',
|
|
676
|
+
'Europe/San_Marino',
|
|
677
|
+
'Europe/Sarajevo',
|
|
678
|
+
'Europe/Saratov',
|
|
679
|
+
'Europe/Simferopol',
|
|
680
|
+
'Europe/Skopje',
|
|
681
|
+
'Europe/Sofia',
|
|
682
|
+
'Europe/Stockholm',
|
|
683
|
+
'Europe/Tallinn',
|
|
684
|
+
'Europe/Tirane',
|
|
685
|
+
'Europe/Tiraspol',
|
|
686
|
+
'Europe/Ulyanovsk',
|
|
687
|
+
'Europe/Uzhgorod',
|
|
688
|
+
'Europe/Vaduz',
|
|
689
|
+
'Europe/Vatican',
|
|
690
|
+
'Europe/Vienna',
|
|
691
|
+
'Europe/Vilnius',
|
|
692
|
+
'Europe/Volgograd',
|
|
693
|
+
'Europe/Warsaw',
|
|
694
|
+
'Europe/Zagreb',
|
|
695
|
+
'Europe/Zaporozhye',
|
|
696
|
+
'Europe/Zurich',
|
|
697
|
+
'GB',
|
|
698
|
+
'GB-Eire',
|
|
699
|
+
'GMT',
|
|
700
|
+
'GMT+0',
|
|
701
|
+
'GMT-0',
|
|
702
|
+
'GMT0',
|
|
703
|
+
'Greenwich',
|
|
704
|
+
'HST',
|
|
705
|
+
'Hongkong',
|
|
706
|
+
'Iceland',
|
|
707
|
+
'Indian/Antananarivo',
|
|
708
|
+
'Indian/Chagos',
|
|
709
|
+
'Indian/Christmas',
|
|
710
|
+
'Indian/Cocos',
|
|
711
|
+
'Indian/Comoro',
|
|
712
|
+
'Indian/Kerguelen',
|
|
713
|
+
'Indian/Mahe',
|
|
714
|
+
'Indian/Maldives',
|
|
715
|
+
'Indian/Mauritius',
|
|
716
|
+
'Indian/Mayotte',
|
|
717
|
+
'Indian/Reunion',
|
|
718
|
+
'Iran',
|
|
719
|
+
'Israel',
|
|
720
|
+
'Jamaica',
|
|
721
|
+
'Japan',
|
|
722
|
+
'Kwajalein',
|
|
723
|
+
'Libya',
|
|
724
|
+
'MET',
|
|
725
|
+
'MST',
|
|
726
|
+
'MST7MDT',
|
|
727
|
+
'Mexico/BajaNorte',
|
|
728
|
+
'Mexico/BajaSur',
|
|
729
|
+
'Mexico/General',
|
|
730
|
+
'NZ',
|
|
731
|
+
'NZ-CHAT',
|
|
732
|
+
'Navajo',
|
|
733
|
+
'PRC',
|
|
734
|
+
'PST8PDT',
|
|
735
|
+
'Pacific/Apia',
|
|
736
|
+
'Pacific/Auckland',
|
|
737
|
+
'Pacific/Bougainville',
|
|
738
|
+
'Pacific/Chatham',
|
|
739
|
+
'Pacific/Chuuk',
|
|
740
|
+
'Pacific/Easter',
|
|
741
|
+
'Pacific/Efate',
|
|
742
|
+
'Pacific/Enderbury',
|
|
743
|
+
'Pacific/Fakaofo',
|
|
744
|
+
'Pacific/Fiji',
|
|
745
|
+
'Pacific/Funafuti',
|
|
746
|
+
'Pacific/Galapagos',
|
|
747
|
+
'Pacific/Gambier',
|
|
748
|
+
'Pacific/Guadalcanal',
|
|
749
|
+
'Pacific/Guam',
|
|
750
|
+
'Pacific/Honolulu',
|
|
751
|
+
'Pacific/Johnston',
|
|
752
|
+
'Pacific/Kiritimati',
|
|
753
|
+
'Pacific/Kosrae',
|
|
754
|
+
'Pacific/Kwajalein',
|
|
755
|
+
'Pacific/Majuro',
|
|
756
|
+
'Pacific/Marquesas',
|
|
757
|
+
'Pacific/Midway',
|
|
758
|
+
'Pacific/Nauru',
|
|
759
|
+
'Pacific/Niue',
|
|
760
|
+
'Pacific/Norfolk',
|
|
761
|
+
'Pacific/Noumea',
|
|
762
|
+
'Pacific/Pago_Pago',
|
|
763
|
+
'Pacific/Palau',
|
|
764
|
+
'Pacific/Pitcairn',
|
|
765
|
+
'Pacific/Pohnpei',
|
|
766
|
+
'Pacific/Ponape',
|
|
767
|
+
'Pacific/Port_Moresby',
|
|
768
|
+
'Pacific/Rarotonga',
|
|
769
|
+
'Pacific/Saipan',
|
|
770
|
+
'Pacific/Samoa',
|
|
771
|
+
'Pacific/Tahiti',
|
|
772
|
+
'Pacific/Tarawa',
|
|
773
|
+
'Pacific/Tongatapu',
|
|
774
|
+
'Pacific/Truk',
|
|
775
|
+
'Pacific/Wake',
|
|
776
|
+
'Pacific/Wallis',
|
|
777
|
+
'Pacific/Yap',
|
|
778
|
+
'Poland',
|
|
779
|
+
'Portugal',
|
|
780
|
+
'ROC',
|
|
781
|
+
'ROK',
|
|
782
|
+
'Singapore',
|
|
783
|
+
'Turkey',
|
|
784
|
+
'UCT',
|
|
785
|
+
'US/Alaska',
|
|
786
|
+
'US/Aleutian',
|
|
787
|
+
'US/Arizona',
|
|
788
|
+
'US/Central',
|
|
789
|
+
'US/East-Indiana',
|
|
790
|
+
'US/Eastern',
|
|
791
|
+
'US/Hawaii',
|
|
792
|
+
'US/Indiana-Starke',
|
|
793
|
+
'US/Michigan',
|
|
794
|
+
'US/Mountain',
|
|
795
|
+
'US/Pacific',
|
|
796
|
+
'US/Pacific-New',
|
|
797
|
+
'US/Samoa',
|
|
798
|
+
'UTC',
|
|
799
|
+
'Universal',
|
|
800
|
+
'W-SU',
|
|
801
|
+
'WET',
|
|
802
|
+
'Zulu'
|
|
803
|
+
];
|
|
804
|
+
const create$5 = (parameters)=>{
|
|
805
|
+
const { timezone } = parameters;
|
|
806
|
+
const now = ()=>{
|
|
807
|
+
return dayjs().tz(timezone).toDate();
|
|
808
|
+
};
|
|
809
|
+
const today = ()=>{
|
|
810
|
+
// Return today's date formatted as YYYY-M-D in the specified timezone
|
|
811
|
+
return dayjs().tz(timezone).format('YYYY-M-D');
|
|
812
|
+
};
|
|
813
|
+
const date = (date)=>{
|
|
814
|
+
let value;
|
|
815
|
+
if (date) {
|
|
816
|
+
value = dayjs.tz(date, timezone);
|
|
817
|
+
} else {
|
|
818
|
+
value = dayjs().tz(timezone);
|
|
819
|
+
}
|
|
820
|
+
if (!value.isValid()) {
|
|
821
|
+
throw new Error(`Invalid date: ${date}`);
|
|
822
|
+
}
|
|
823
|
+
return value.toDate();
|
|
824
|
+
};
|
|
825
|
+
const parse = (date, format)=>{
|
|
826
|
+
const value = dayjs.tz(date, format, timezone);
|
|
827
|
+
if (!value.isValid()) {
|
|
828
|
+
throw new Error(`Invalid date: ${date}, expected format: ${format}`);
|
|
829
|
+
}
|
|
830
|
+
return value.toDate();
|
|
831
|
+
};
|
|
832
|
+
const isValidDate = (date, format)=>{
|
|
833
|
+
return dayjs(date, format, true).isValid(); // Use strict parsing
|
|
834
|
+
};
|
|
835
|
+
const addDays = (date, days)=>{
|
|
836
|
+
return dayjs.tz(date, timezone).add(days, 'day').toDate();
|
|
837
|
+
};
|
|
838
|
+
const addMonths = (date, months)=>{
|
|
839
|
+
return dayjs.tz(date, timezone).add(months, 'month').toDate();
|
|
840
|
+
};
|
|
841
|
+
const addYears = (date, years)=>{
|
|
842
|
+
return dayjs.tz(date, timezone).add(years, 'year').toDate();
|
|
843
|
+
};
|
|
844
|
+
const format = (date, format)=>{
|
|
845
|
+
return dayjs.tz(date, timezone).format(format);
|
|
846
|
+
};
|
|
847
|
+
const subDays = (date, days)=>{
|
|
848
|
+
return dayjs.tz(date, timezone).subtract(days, 'day').toDate();
|
|
849
|
+
};
|
|
850
|
+
const subMonths = (date, months)=>{
|
|
851
|
+
return dayjs.tz(date, timezone).subtract(months, 'month').toDate();
|
|
852
|
+
};
|
|
853
|
+
const subYears = (date, years)=>{
|
|
854
|
+
return dayjs.tz(date, timezone).subtract(years, 'year').toDate();
|
|
855
|
+
};
|
|
856
|
+
const startOfMonth = (date)=>{
|
|
857
|
+
return dayjs.tz(date, timezone).startOf('month').toDate();
|
|
858
|
+
};
|
|
859
|
+
const endOfMonth = (date)=>{
|
|
860
|
+
return dayjs.tz(date, timezone).endOf('month').toDate();
|
|
861
|
+
};
|
|
862
|
+
const startOfYear = (date)=>{
|
|
863
|
+
return dayjs.tz(date, timezone).startOf('year').toDate();
|
|
864
|
+
};
|
|
865
|
+
const endOfYear = (date)=>{
|
|
866
|
+
return dayjs.tz(date, timezone).endOf('year').toDate();
|
|
867
|
+
};
|
|
868
|
+
const isBefore = (date, other)=>{
|
|
869
|
+
return dayjs.tz(date, timezone).isBefore(dayjs.tz(other, timezone));
|
|
870
|
+
};
|
|
871
|
+
const isAfter = (date, other)=>{
|
|
872
|
+
return dayjs.tz(date, timezone).isAfter(dayjs.tz(other, timezone));
|
|
873
|
+
};
|
|
874
|
+
return {
|
|
875
|
+
now,
|
|
876
|
+
today,
|
|
877
|
+
date,
|
|
878
|
+
parse,
|
|
879
|
+
isValidDate,
|
|
880
|
+
addDays,
|
|
881
|
+
addMonths,
|
|
882
|
+
addYears,
|
|
883
|
+
format,
|
|
884
|
+
subDays,
|
|
885
|
+
subMonths,
|
|
886
|
+
subYears,
|
|
887
|
+
startOfMonth,
|
|
888
|
+
endOfMonth,
|
|
889
|
+
startOfYear,
|
|
890
|
+
endOfYear,
|
|
891
|
+
isBefore,
|
|
892
|
+
isAfter
|
|
893
|
+
};
|
|
894
|
+
};
|
|
895
|
+
const validTimezones = ()=>{
|
|
896
|
+
return TIMEZONE_NAMES;
|
|
897
|
+
};
|
|
898
|
+
|
|
899
|
+
const create$4 = (params)=>{
|
|
900
|
+
// eslint-disable-next-line no-console
|
|
901
|
+
const log = params.log || console.log;
|
|
902
|
+
const exists = async (path)=>{
|
|
903
|
+
try {
|
|
904
|
+
await fs__namespace.promises.stat(path);
|
|
905
|
+
return true;
|
|
906
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
907
|
+
} catch (error) {
|
|
908
|
+
return false;
|
|
909
|
+
}
|
|
910
|
+
};
|
|
911
|
+
const isDirectory = async (path)=>{
|
|
912
|
+
const stats = await fs__namespace.promises.stat(path);
|
|
913
|
+
if (!stats.isDirectory()) {
|
|
914
|
+
log(`${path} is not a directory`);
|
|
915
|
+
return false;
|
|
916
|
+
}
|
|
917
|
+
return true;
|
|
918
|
+
};
|
|
919
|
+
const isFile = async (path)=>{
|
|
920
|
+
const stats = await fs__namespace.promises.stat(path);
|
|
921
|
+
if (!stats.isFile()) {
|
|
922
|
+
log(`${path} is not a file`);
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
return true;
|
|
926
|
+
};
|
|
927
|
+
const isReadable = async (path)=>{
|
|
928
|
+
try {
|
|
929
|
+
await fs__namespace.promises.access(path, fs__namespace.constants.R_OK);
|
|
930
|
+
} catch (error) {
|
|
931
|
+
log(`${path} is not readable: %s %s`, error.message, error.stack);
|
|
932
|
+
return false;
|
|
933
|
+
}
|
|
934
|
+
return true;
|
|
935
|
+
};
|
|
936
|
+
const isWritable = async (path)=>{
|
|
937
|
+
try {
|
|
938
|
+
await fs__namespace.promises.access(path, fs__namespace.constants.W_OK);
|
|
939
|
+
} catch (error) {
|
|
940
|
+
log(`${path} is not writable: %s %s`, error.message, error.stack);
|
|
941
|
+
return false;
|
|
942
|
+
}
|
|
943
|
+
return true;
|
|
944
|
+
};
|
|
945
|
+
const isFileReadable = async (path)=>{
|
|
946
|
+
return await exists(path) && await isFile(path) && await isReadable(path);
|
|
947
|
+
};
|
|
948
|
+
const isDirectoryWritable = async (path)=>{
|
|
949
|
+
return await exists(path) && await isDirectory(path) && await isWritable(path);
|
|
950
|
+
};
|
|
951
|
+
const isDirectoryReadable = async (path)=>{
|
|
952
|
+
return await exists(path) && await isDirectory(path) && await isReadable(path);
|
|
953
|
+
};
|
|
954
|
+
const createDirectory = async (path)=>{
|
|
955
|
+
try {
|
|
956
|
+
await fs__namespace.promises.mkdir(path, {
|
|
957
|
+
recursive: true
|
|
958
|
+
});
|
|
959
|
+
} catch (mkdirError) {
|
|
960
|
+
throw new Error(`Failed to create output directory ${path}: ${mkdirError.message} ${mkdirError.stack}`);
|
|
961
|
+
}
|
|
962
|
+
};
|
|
963
|
+
const readFile = async (path, encoding)=>{
|
|
964
|
+
return await fs__namespace.promises.readFile(path, {
|
|
965
|
+
encoding: encoding
|
|
966
|
+
});
|
|
967
|
+
};
|
|
968
|
+
const writeFile = async (path, data, encoding)=>{
|
|
969
|
+
await fs__namespace.promises.writeFile(path, data, {
|
|
970
|
+
encoding: encoding
|
|
971
|
+
});
|
|
972
|
+
};
|
|
973
|
+
const forEachFileIn = async (directory, callback, options = {
|
|
974
|
+
pattern: '*.*'
|
|
975
|
+
})=>{
|
|
976
|
+
try {
|
|
977
|
+
let filesProcessed = 0;
|
|
978
|
+
const files = await glob.glob(options.pattern, {
|
|
979
|
+
cwd: directory,
|
|
980
|
+
nodir: true
|
|
981
|
+
});
|
|
982
|
+
const concurrency = options.concurrency || 1;
|
|
983
|
+
let index = 0;
|
|
984
|
+
async function worker() {
|
|
985
|
+
while(index < files.length && (!options.limit || filesProcessed < options.limit)){
|
|
986
|
+
const i = index++;
|
|
987
|
+
if (options.limit && filesProcessed >= options.limit) break;
|
|
988
|
+
await callback(path__namespace.join(directory, files[i]));
|
|
989
|
+
filesProcessed++;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
const workers = Array.from({
|
|
993
|
+
length: concurrency
|
|
994
|
+
}, ()=>worker());
|
|
995
|
+
await Promise.all(workers);
|
|
996
|
+
if (options.limit && filesProcessed >= options.limit) {
|
|
997
|
+
log(`Reached limit of ${options.limit} files, stopping`);
|
|
998
|
+
}
|
|
999
|
+
} catch (err) {
|
|
1000
|
+
throw new Error(`Failed to glob pattern ${options.pattern} in ${directory}: ${err.message}`);
|
|
1001
|
+
}
|
|
1002
|
+
};
|
|
1003
|
+
const readStream = async (path)=>{
|
|
1004
|
+
return fs__namespace.createReadStream(path);
|
|
1005
|
+
};
|
|
1006
|
+
const hashFile = async (path, length)=>{
|
|
1007
|
+
const file = await readFile(path, 'utf8');
|
|
1008
|
+
return crypto__namespace.createHash('sha256').update(file).digest('hex').slice(0, length);
|
|
1009
|
+
};
|
|
1010
|
+
const listFiles = async (directory)=>{
|
|
1011
|
+
return await fs__namespace.promises.readdir(directory);
|
|
1012
|
+
};
|
|
1013
|
+
return {
|
|
1014
|
+
exists,
|
|
1015
|
+
isDirectory,
|
|
1016
|
+
isFile,
|
|
1017
|
+
isReadable,
|
|
1018
|
+
isWritable,
|
|
1019
|
+
isFileReadable,
|
|
1020
|
+
isDirectoryWritable,
|
|
1021
|
+
isDirectoryReadable,
|
|
1022
|
+
createDirectory,
|
|
1023
|
+
readFile,
|
|
1024
|
+
readStream,
|
|
1025
|
+
writeFile,
|
|
1026
|
+
forEachFileIn,
|
|
1027
|
+
hashFile,
|
|
1028
|
+
listFiles
|
|
1029
|
+
};
|
|
1030
|
+
};
|
|
1031
|
+
|
|
1032
|
+
const validate = async (config, options)=>{
|
|
1033
|
+
const logger = console;
|
|
1034
|
+
const storage = create$4({
|
|
1035
|
+
log: logger.debug
|
|
1036
|
+
});
|
|
1037
|
+
const validateInputDirectory = async (inputDirectory)=>{
|
|
1038
|
+
// eslint-disable-next-line no-console
|
|
1039
|
+
const storage = create$4({
|
|
1040
|
+
log: console.log
|
|
1041
|
+
});
|
|
1042
|
+
if (!storage.isDirectoryReadable(inputDirectory)) {
|
|
1043
|
+
throw new Error(`Input directory does not exist: ${inputDirectory}`);
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
const validateOutputDirectory = async (outputDirectory)=>{
|
|
1047
|
+
const isDirectoryWritable = await storage.isDirectoryWritable(outputDirectory);
|
|
1048
|
+
if (!isDirectoryWritable) {
|
|
1049
|
+
throw new Error(`Output directory does not exist: ${outputDirectory}`);
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
const validateOutputStructure = (outputStructure)=>{
|
|
1053
|
+
var _options_allowed;
|
|
1054
|
+
const validOptions = ((_options_allowed = options.allowed) === null || _options_allowed === void 0 ? void 0 : _options_allowed.outputStructures) || ALLOWED_OUTPUT_STRUCTURES;
|
|
1055
|
+
if (outputStructure && !validOptions.includes(outputStructure)) {
|
|
1056
|
+
throw new ArgumentError('--output-structure', `Invalid output structure: ${outputStructure}. Valid options are: ${validOptions.join(', ')}`);
|
|
1057
|
+
}
|
|
1058
|
+
};
|
|
1059
|
+
const validateOutputFilenameOptions = (outputFilenameOptions, outputStructure)=>{
|
|
1060
|
+
if (outputFilenameOptions) {
|
|
1061
|
+
var _options_allowed;
|
|
1062
|
+
// Check if first argument contains commas - likely a comma-separated list
|
|
1063
|
+
if (outputFilenameOptions[0].includes(',')) {
|
|
1064
|
+
throw new ArgumentError('--output-filename-options', 'Filename options should be space-separated, not comma-separated. Example: --output-filename-options date time subject');
|
|
1065
|
+
}
|
|
1066
|
+
// Check if first argument looks like a quoted string containing multiple options
|
|
1067
|
+
if (outputFilenameOptions.length === 1 && outputFilenameOptions[0].split(' ').length > 1) {
|
|
1068
|
+
throw new ArgumentError('--output-filename-options', 'Filename options should not be quoted. Use: --output-filename-options date time subject instead of --output-filename-options "date time subject"');
|
|
1069
|
+
}
|
|
1070
|
+
const validOptions = ((_options_allowed = options.allowed) === null || _options_allowed === void 0 ? void 0 : _options_allowed.outputFilenameOptions) || ALLOWED_OUTPUT_FILENAME_OPTIONS;
|
|
1071
|
+
const invalidOptions = outputFilenameOptions.filter((opt)=>!validOptions.includes(opt));
|
|
1072
|
+
if (invalidOptions.length > 0) {
|
|
1073
|
+
throw new ArgumentError('--output-filename-options', `Invalid filename options: ${invalidOptions.join(', ')}. Valid options are: ${validOptions.join(', ')}`);
|
|
1074
|
+
}
|
|
1075
|
+
// Validate date option against output structure
|
|
1076
|
+
if (outputFilenameOptions.includes('date')) {
|
|
1077
|
+
if (outputStructure && outputStructure === 'day') {
|
|
1078
|
+
throw new ArgumentError('--output-filename-options', 'Cannot use date in filename when output structure is "day"');
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
};
|
|
1083
|
+
const validateInputStructure = (inputStructure)=>{
|
|
1084
|
+
var _options_allowed;
|
|
1085
|
+
const validOptions = ((_options_allowed = options.allowed) === null || _options_allowed === void 0 ? void 0 : _options_allowed.inputStructures) || ALLOWED_INPUT_STRUCTURES;
|
|
1086
|
+
if (inputStructure && !validOptions.includes(inputStructure)) {
|
|
1087
|
+
throw new ArgumentError('--input-structure', `Invalid input structure: ${inputStructure}. Valid options are: ${validOptions.join(', ')}`);
|
|
1088
|
+
}
|
|
1089
|
+
};
|
|
1090
|
+
const validateInputFilenameOptions = (inputFilenameOptions, inputStructure)=>{
|
|
1091
|
+
if (inputFilenameOptions) {
|
|
1092
|
+
var _options_allowed;
|
|
1093
|
+
// Check if first argument contains commas - likely a comma-separated list
|
|
1094
|
+
if (inputFilenameOptions[0].includes(',')) {
|
|
1095
|
+
throw new ArgumentError('--input-filename-options', 'Filename options should be space-separated, not comma-separated. Example: --input-filename-options date time subject');
|
|
1096
|
+
}
|
|
1097
|
+
// Check if first argument looks like a quoted string containing multiple options
|
|
1098
|
+
if (inputFilenameOptions.length === 1 && inputFilenameOptions[0].split(' ').length > 1) {
|
|
1099
|
+
throw new ArgumentError('--input-filename-options', 'Filename options should not be quoted. Use: --input-filename-options date time subject instead of --input-filename-options "date time subject"');
|
|
1100
|
+
}
|
|
1101
|
+
const validOptions = ((_options_allowed = options.allowed) === null || _options_allowed === void 0 ? void 0 : _options_allowed.inputFilenameOptions) || ALLOWED_INPUT_FILENAME_OPTIONS;
|
|
1102
|
+
const invalidOptions = inputFilenameOptions.filter((opt)=>!validOptions.includes(opt));
|
|
1103
|
+
if (invalidOptions.length > 0) {
|
|
1104
|
+
throw new ArgumentError('--input-filename-options', `Invalid filename options: ${invalidOptions.join(', ')}. Valid options are: ${validOptions.join(', ')}`);
|
|
1105
|
+
}
|
|
1106
|
+
// Validate date option against input structure
|
|
1107
|
+
if (inputFilenameOptions.includes('date')) {
|
|
1108
|
+
if (inputStructure && inputStructure === 'day') {
|
|
1109
|
+
throw new ArgumentError('--input-filename-options', 'Cannot use date in filename when input structure is "day"');
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
};
|
|
1114
|
+
const validateTimezone = (timezone)=>{
|
|
1115
|
+
const validOptions = validTimezones();
|
|
1116
|
+
if (validOptions.includes(timezone)) {
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
throw new ArgumentError('--timezone', `Invalid timezone: ${timezone}. Valid options are: ${validOptions.join(', ')}`);
|
|
1120
|
+
};
|
|
1121
|
+
const validateExtensions = (extensions)=>{
|
|
1122
|
+
var _options_allowed;
|
|
1123
|
+
const validOptions = ((_options_allowed = options.allowed) === null || _options_allowed === void 0 ? void 0 : _options_allowed.extensions) || ALLOWED_EXTENSIONS;
|
|
1124
|
+
if (extensions) {
|
|
1125
|
+
const invalidOptions = extensions.filter((ext)=>!validOptions.includes(ext));
|
|
1126
|
+
if (invalidOptions.length > 0) {
|
|
1127
|
+
throw new ArgumentError('--extensions', `Invalid extensions: ${invalidOptions.join(', ')}. Valid options are: ${validOptions.join(', ')}`);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
};
|
|
1131
|
+
// Validate timezone
|
|
1132
|
+
validateTimezone(config.timezone);
|
|
1133
|
+
if (options.features.includes('input') && config.inputDirectory) {
|
|
1134
|
+
await validateInputDirectory(config.inputDirectory);
|
|
1135
|
+
}
|
|
1136
|
+
if (options.features.includes('input') && config.limit) {
|
|
1137
|
+
if (config.limit < 1) {
|
|
1138
|
+
throw new ArgumentError('--limit', 'Limit must be greater than 0');
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
if (options.features.includes('output') && config.outputDirectory) {
|
|
1142
|
+
await validateOutputDirectory(config.outputDirectory);
|
|
1143
|
+
}
|
|
1144
|
+
if (options.features.includes('structured-output')) {
|
|
1145
|
+
// Validate filename options if provided
|
|
1146
|
+
validateOutputStructure(config.outputStructure);
|
|
1147
|
+
validateOutputFilenameOptions(config.outputFilenameOptions, config.outputStructure);
|
|
1148
|
+
}
|
|
1149
|
+
if (options.features.includes('extensions')) {
|
|
1150
|
+
validateExtensions(config.extensions);
|
|
1151
|
+
}
|
|
1152
|
+
if (options.features.includes('structured-input')) {
|
|
1153
|
+
validateInputStructure(config.inputStructure);
|
|
1154
|
+
validateInputFilenameOptions(config.inputFilenameOptions, config.inputStructure);
|
|
1155
|
+
}
|
|
1156
|
+
return;
|
|
1157
|
+
};
|
|
1158
|
+
|
|
1159
|
+
zod.z.object({
|
|
1160
|
+
start: zod.z.date(),
|
|
1161
|
+
end: zod.z.date()
|
|
1162
|
+
});
|
|
1163
|
+
// Get the appropriate file pattern based on config and options
|
|
1164
|
+
const getFilePattern = (features, extensions, logger)=>{
|
|
1165
|
+
// Validate extensions: they should not start with a dot.
|
|
1166
|
+
if (extensions && extensions.length > 0) {
|
|
1167
|
+
for (const ext of extensions){
|
|
1168
|
+
if (ext.startsWith('.')) {
|
|
1169
|
+
// Throw an error as the dot is added automatically by the pattern generation.
|
|
1170
|
+
// Using ArgumentError might be more consistent if available and appropriate here.
|
|
1171
|
+
throw new Error(`Invalid extension format: "${ext}". Extensions should not start with a dot ('.').`);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
let pattern = '**/*'; // Start with a broad pattern for recursive search
|
|
1176
|
+
if (features.includes('extensions') && extensions && extensions.length > 0) {
|
|
1177
|
+
if (extensions.length === 1) {
|
|
1178
|
+
pattern = `**/*.${extensions[0]}`;
|
|
1179
|
+
} else {
|
|
1180
|
+
pattern = `**/*.{${extensions.join(',')}}`;
|
|
1181
|
+
}
|
|
1182
|
+
logger.debug(`Applying extension filter: ${extensions.join(',')}`);
|
|
1183
|
+
} else {
|
|
1184
|
+
pattern = `**/*.*`;
|
|
1185
|
+
logger.debug(`No extension filter applied, using pattern: ${pattern}`);
|
|
1186
|
+
}
|
|
1187
|
+
return pattern;
|
|
1188
|
+
};
|
|
1189
|
+
// Helper function to parse date string based on expected format
|
|
1190
|
+
// Returns null if parsing fails
|
|
1191
|
+
const parseDateFromString = (dateStr, format, shouldParseTime, year, month, day)=>{
|
|
1192
|
+
// Basic validation
|
|
1193
|
+
if (!dateStr) return null;
|
|
1194
|
+
try {
|
|
1195
|
+
let y = year !== null && year !== void 0 ? year : 0;
|
|
1196
|
+
let mo = month !== null && month !== void 0 ? month : 0; // JS months are 0-indexed
|
|
1197
|
+
let d = day !== null && day !== void 0 ? day : 1; // JS days are 1-indexed
|
|
1198
|
+
let h = 0; // Default to 0
|
|
1199
|
+
let mi = 0; // Default to 0
|
|
1200
|
+
// Remove potential leading/trailing non-alphanumeric if needed, split by common separators
|
|
1201
|
+
const cleanedDateStr = dateStr.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu, '');
|
|
1202
|
+
const parts = cleanedDateStr.split(/[-_]/); // Allow dash or underscore
|
|
1203
|
+
switch(format){
|
|
1204
|
+
case 'YYYY-M-D-HHmm':
|
|
1205
|
+
{
|
|
1206
|
+
if (parts.length < 4 && shouldParseTime) return null; // Need time part if parsing it
|
|
1207
|
+
if (parts.length < 3 && !shouldParseTime) return null; // Need at least date part
|
|
1208
|
+
y = parseInt(parts[0], 10);
|
|
1209
|
+
mo = parseInt(parts[1], 10) - 1; // Adjust month
|
|
1210
|
+
d = parseInt(parts[2], 10);
|
|
1211
|
+
if (shouldParseTime) {
|
|
1212
|
+
const timePartYD = parts[3];
|
|
1213
|
+
if (timePartYD.length < 4) return null; // Ensure HHmm exists
|
|
1214
|
+
h = parseInt(timePartYD.substring(0, 2), 10);
|
|
1215
|
+
mi = parseInt(timePartYD.substring(2, 4), 10);
|
|
1216
|
+
}
|
|
1217
|
+
break;
|
|
1218
|
+
}
|
|
1219
|
+
case 'M-D-HHmm':
|
|
1220
|
+
{
|
|
1221
|
+
if (year === undefined) return null;
|
|
1222
|
+
if (parts.length < 3 && shouldParseTime) return null;
|
|
1223
|
+
if (parts.length < 2 && !shouldParseTime) return null;
|
|
1224
|
+
mo = parseInt(parts[0], 10) - 1; // Adjust month
|
|
1225
|
+
d = parseInt(parts[1], 10);
|
|
1226
|
+
if (shouldParseTime) {
|
|
1227
|
+
const timePartMD = parts[2];
|
|
1228
|
+
if (timePartMD.length < 4) return null; // Ensure HHmm exists
|
|
1229
|
+
h = parseInt(timePartMD.substring(0, 2), 10);
|
|
1230
|
+
mi = parseInt(timePartMD.substring(2, 4), 10);
|
|
1231
|
+
}
|
|
1232
|
+
break;
|
|
1233
|
+
}
|
|
1234
|
+
case 'D-HHmm':
|
|
1235
|
+
{
|
|
1236
|
+
if (year === undefined || month === undefined) return null;
|
|
1237
|
+
if (parts.length < 2 && shouldParseTime) return null;
|
|
1238
|
+
if (parts.length < 1 && !shouldParseTime) return null;
|
|
1239
|
+
d = parseInt(parts[0], 10);
|
|
1240
|
+
if (shouldParseTime) {
|
|
1241
|
+
const timePartD = parts[1];
|
|
1242
|
+
if (timePartD.length < 4) return null; // Ensure HHmm exists
|
|
1243
|
+
h = parseInt(timePartD.substring(0, 2), 10);
|
|
1244
|
+
mi = parseInt(timePartD.substring(2, 4), 10);
|
|
1245
|
+
}
|
|
1246
|
+
break;
|
|
1247
|
+
}
|
|
1248
|
+
case 'HHmm':
|
|
1249
|
+
if (year === undefined || month === undefined || day === undefined) return null;
|
|
1250
|
+
if (shouldParseTime) {
|
|
1251
|
+
if (parts[0].length !== 4) return null;
|
|
1252
|
+
h = parseInt(parts[0].substring(0, 2), 10);
|
|
1253
|
+
mi = parseInt(parts[0].substring(2, 4), 10);
|
|
1254
|
+
} // Else h=0, mi=0 (set by defaults)
|
|
1255
|
+
break;
|
|
1256
|
+
default:
|
|
1257
|
+
return null;
|
|
1258
|
+
}
|
|
1259
|
+
// Validate parsed numbers
|
|
1260
|
+
if (isNaN(y) || isNaN(mo) || isNaN(d)) {
|
|
1261
|
+
throw new Error(`Invalid date components in date string "${dateStr}" with format ${format}: Y:${y} M:${mo} D:${d}`);
|
|
1262
|
+
}
|
|
1263
|
+
// Set hour and minute to 0 if not provided
|
|
1264
|
+
if (isNaN(h)) {
|
|
1265
|
+
h = 0;
|
|
1266
|
+
}
|
|
1267
|
+
if (isNaN(mi)) {
|
|
1268
|
+
mi = 0;
|
|
1269
|
+
}
|
|
1270
|
+
if (mo < 0 || mo > 11 || d < 1 || d > 31 || h < 0 || h > 23 || mi < 0 || mi > 59) {
|
|
1271
|
+
throw new Error(`Invalid date components in date string "${dateStr}" with format ${format}: Y:${y} M:${mo + 1} D:${d} H:${h} m:${mi}`);
|
|
1272
|
+
}
|
|
1273
|
+
const date = new Date(Date.UTC(y, mo, d, h, mi));
|
|
1274
|
+
// Double check components as Date object might adjust invalid dates (e.g. Feb 30th -> Mar 2nd)
|
|
1275
|
+
if (date.getUTCFullYear() !== y || date.getUTCMonth() !== mo || date.getUTCDate() !== d || date.getUTCHours() !== h || date.getUTCMinutes() !== mi) {
|
|
1276
|
+
// console.debug(`Date validation failed for Y:${y} M:${mo} D:${d} H:${h} m:${mi}. JS Date adjusted it.`);
|
|
1277
|
+
return null;
|
|
1278
|
+
}
|
|
1279
|
+
return date;
|
|
1280
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1281
|
+
} catch (e) {
|
|
1282
|
+
// console.error(`Error parsing date string "${dateStr}" with format ${format}:`, e);
|
|
1283
|
+
return null;
|
|
1284
|
+
}
|
|
1285
|
+
};
|
|
1286
|
+
// Helper to check if date is within range (start inclusive, end exclusive)
|
|
1287
|
+
const isDateInRange = (date, range)=>{
|
|
1288
|
+
if (!range || !range.start && !range.end) return true; // No range or empty range means all dates are valid
|
|
1289
|
+
// Ensure range dates are Date objects
|
|
1290
|
+
const startDate = range.start ? range.start instanceof Date ? range.start : new Date(range.start) : null;
|
|
1291
|
+
const endDate = range.end ? range.end instanceof Date ? range.end : new Date(range.end) : null;
|
|
1292
|
+
// Validate parsed range dates
|
|
1293
|
+
const isStartDateValid = startDate && !isNaN(startDate.getTime());
|
|
1294
|
+
const isEndDateValid = endDate && !isNaN(endDate.getTime());
|
|
1295
|
+
if (isStartDateValid && date < startDate) {
|
|
1296
|
+
return false;
|
|
1297
|
+
}
|
|
1298
|
+
// End date is exclusive
|
|
1299
|
+
if (isEndDateValid && date >= endDate) {
|
|
1300
|
+
return false;
|
|
1301
|
+
}
|
|
1302
|
+
return true;
|
|
1303
|
+
};
|
|
1304
|
+
const calculateDateRange = (timezone, startDate, endDate)=>{
|
|
1305
|
+
// Create date utility after timezone is validated
|
|
1306
|
+
const dateUtil = create$5({
|
|
1307
|
+
timezone
|
|
1308
|
+
});
|
|
1309
|
+
const now = dateUtil.now();
|
|
1310
|
+
const range = {
|
|
1311
|
+
start: dateUtil.subDays(now, 31),
|
|
1312
|
+
end: now
|
|
1313
|
+
};
|
|
1314
|
+
// Note: Validation ensures dates are valid and start <= end if both are provided
|
|
1315
|
+
if (startDate || endDate) {
|
|
1316
|
+
// Handle end date
|
|
1317
|
+
if (endDate) {
|
|
1318
|
+
range.end = dateUtil.parse(endDate, DATE_FORMAT_YEAR_MONTH_DAY);
|
|
1319
|
+
}
|
|
1320
|
+
// Handle start date
|
|
1321
|
+
if (startDate) {
|
|
1322
|
+
range.start = dateUtil.parse(startDate, DATE_FORMAT_YEAR_MONTH_DAY);
|
|
1323
|
+
}
|
|
1324
|
+
// We re-check the order here after defaults might have been applied,
|
|
1325
|
+
// although validateStartEndDates should catch explicit invalid orders.
|
|
1326
|
+
if (dateUtil.isBefore(range.end, range.start)) {
|
|
1327
|
+
// This case should theoretically not be reachable due to prior validation
|
|
1328
|
+
// but is kept as a safeguard.
|
|
1329
|
+
throw new ArgumentError('--start', `Start date (${dateUtil.format(range.start, DATE_FORMAT_YEAR_MONTH_DAY)}) cannot be after end date (${dateUtil.format(range.end, DATE_FORMAT_YEAR_MONTH_DAY)}).`);
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
return range;
|
|
1333
|
+
};
|
|
1334
|
+
// Parse date from file path based on the input structure
|
|
1335
|
+
const parseDateFromFilePath = (relativePath, filename, structure, shouldParseTime, logger)=>{
|
|
1336
|
+
const pathParts = relativePath.split(path__namespace.sep);
|
|
1337
|
+
const filenameWithoutExt = path__namespace.basename(filename, path__namespace.extname(filename));
|
|
1338
|
+
let parsedDate = null;
|
|
1339
|
+
let year;
|
|
1340
|
+
let month; // 0-indexed month for Date constructor
|
|
1341
|
+
let day;
|
|
1342
|
+
switch(structure){
|
|
1343
|
+
case 'none':
|
|
1344
|
+
// Filename format: YYYY-M-D-HHmm...
|
|
1345
|
+
parsedDate = parseDateFromString(filenameWithoutExt, 'YYYY-M-D-HHmm', shouldParseTime);
|
|
1346
|
+
break;
|
|
1347
|
+
case 'year':
|
|
1348
|
+
// Path: YYYY / M-D-HHmm...
|
|
1349
|
+
if (pathParts.length >= 1) {
|
|
1350
|
+
year = parseInt(pathParts[0], 10);
|
|
1351
|
+
if (!isNaN(year)) {
|
|
1352
|
+
parsedDate = parseDateFromString(filenameWithoutExt, 'M-D-HHmm', shouldParseTime, year);
|
|
1353
|
+
} else {
|
|
1354
|
+
logger.warn(`Invalid year format in path: ${pathParts[0]}`);
|
|
1355
|
+
}
|
|
1356
|
+
} else {
|
|
1357
|
+
logger.warn(`File path does not match expected 'year' structure (YYYY/...)`);
|
|
1358
|
+
}
|
|
1359
|
+
break;
|
|
1360
|
+
case 'month':
|
|
1361
|
+
// Path: YYYY / MM / D-HHmm...
|
|
1362
|
+
if (pathParts.length >= 2) {
|
|
1363
|
+
year = parseInt(pathParts[0], 10);
|
|
1364
|
+
const monthDir = parseInt(pathParts[1], 10); // Month from dir (1-indexed)
|
|
1365
|
+
if (!isNaN(year) && !isNaN(monthDir) && monthDir >= 1 && monthDir <= 12) {
|
|
1366
|
+
month = monthDir - 1; // Adjust month for Date object (0-indexed)
|
|
1367
|
+
parsedDate = parseDateFromString(filenameWithoutExt, 'D-HHmm', shouldParseTime, year, month);
|
|
1368
|
+
} else {
|
|
1369
|
+
logger.warn(`Invalid year/month format in path: ${pathParts[0]}/${pathParts[1]}`);
|
|
1370
|
+
}
|
|
1371
|
+
} else {
|
|
1372
|
+
logger.warn(`File path does not match expected 'month' structure (YYYY/MM/...)`);
|
|
1373
|
+
}
|
|
1374
|
+
break;
|
|
1375
|
+
case 'day':
|
|
1376
|
+
// Path: YYYY / MM / DD / HHmm...
|
|
1377
|
+
if (pathParts.length >= 3) {
|
|
1378
|
+
year = parseInt(pathParts[0], 10);
|
|
1379
|
+
const monthDir = parseInt(pathParts[1], 10); // Month from dir (1-indexed)
|
|
1380
|
+
day = parseInt(pathParts[2], 10); // Day from dir (1-indexed)
|
|
1381
|
+
if (!isNaN(year) && !isNaN(monthDir) && monthDir >= 1 && monthDir <= 12 && !isNaN(day) && day >= 1 && day <= 31) {
|
|
1382
|
+
month = monthDir - 1; // Adjust month (0-indexed)
|
|
1383
|
+
parsedDate = parseDateFromString(filenameWithoutExt, 'HHmm', shouldParseTime, year, month, day);
|
|
1384
|
+
} else {
|
|
1385
|
+
logger.warn(`Invalid year/month/day format in path: ${pathParts[0]}/${pathParts[1]}/${pathParts[2]}`);
|
|
1386
|
+
}
|
|
1387
|
+
} else {
|
|
1388
|
+
logger.warn(`File path does not match expected 'day' structure (YYYY/MM/DD/...)`);
|
|
1389
|
+
}
|
|
1390
|
+
break;
|
|
1391
|
+
default:
|
|
1392
|
+
logger.error(`Fatal: Unknown input structure "${structure}" specified in config.`);
|
|
1393
|
+
throw new Error(`Unknown input structure "${structure}" specified.`);
|
|
1394
|
+
}
|
|
1395
|
+
return parsedDate;
|
|
1396
|
+
};
|
|
1397
|
+
// Process a single file from the structured input
|
|
1398
|
+
const processStructuredFile = async (filePath, inputDirectory, structure, shouldParseTime, callback, pattern, dateRange, logger)=>{
|
|
1399
|
+
// Skip if filePath somehow points to the inputDirectory itself or is not a file
|
|
1400
|
+
if (filePath === inputDirectory || !path__namespace.extname(filePath) && pattern.endsWith('*.*')) {
|
|
1401
|
+
return false;
|
|
1402
|
+
}
|
|
1403
|
+
const relativePath = path__namespace.relative(inputDirectory, filePath);
|
|
1404
|
+
const pathParts = relativePath.split(path__namespace.sep);
|
|
1405
|
+
const filename = pathParts.pop(); // Filename is the last part
|
|
1406
|
+
if (!filename) {
|
|
1407
|
+
logger.warn(`Could not determine filename for path: ${filePath}`);
|
|
1408
|
+
return false;
|
|
1409
|
+
}
|
|
1410
|
+
try {
|
|
1411
|
+
const parsedDate = parseDateFromFilePath(relativePath, filename, structure, shouldParseTime, logger);
|
|
1412
|
+
if (parsedDate) {
|
|
1413
|
+
// Apply date range filtering
|
|
1414
|
+
if (isDateInRange(parsedDate, dateRange)) {
|
|
1415
|
+
logger.debug('Processing file %s with date %s', filePath, parsedDate.toISOString());
|
|
1416
|
+
await callback(filePath, parsedDate);
|
|
1417
|
+
return true;
|
|
1418
|
+
} else {
|
|
1419
|
+
const dateRangeDisplay = dateRange ? `from ${dateRange.start ? new Date(dateRange.start).toISOString() : 'beginning'} up to ${dateRange.end ? new Date(dateRange.end).toISOString() : 'end'}` : 'all dates';
|
|
1420
|
+
logger.debug('Skipping file %s, date %s out of range %s', filePath, parsedDate.toISOString(), dateRangeDisplay);
|
|
1421
|
+
}
|
|
1422
|
+
} else {
|
|
1423
|
+
logger.warn('Could not parse date for file %s with structure "%s" (filename base: "%s", path parts: %s)', filePath, structure, path__namespace.basename(filename, path__namespace.extname(filename)), pathParts.join('/'));
|
|
1424
|
+
}
|
|
1425
|
+
} catch (error) {
|
|
1426
|
+
// Log error from the callback or date parsing/filtering itself
|
|
1427
|
+
if (error instanceof Error) {
|
|
1428
|
+
logger.error('Error processing file %s: %s\n%s', filePath, error.message, error.stack);
|
|
1429
|
+
} else {
|
|
1430
|
+
logger.error('Error processing file %s: %s', filePath, error);
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
return false;
|
|
1434
|
+
};
|
|
1435
|
+
const process$2 = async (inputStructure, inputFilenameOptions, extensions, timezone, start, end, limit, features, logger, inputDirectory, callback, concurrency)=>{
|
|
1436
|
+
var _ref;
|
|
1437
|
+
const storage = create$4({
|
|
1438
|
+
log: logger.debug
|
|
1439
|
+
});
|
|
1440
|
+
const dateRange = calculateDateRange(timezone, start, end);
|
|
1441
|
+
let fileCount = 0;
|
|
1442
|
+
// Validate date range dates if provided
|
|
1443
|
+
if ((dateRange === null || dateRange === void 0 ? void 0 : dateRange.start) && (!dateRange.start || isNaN(dateRange.start.getTime()))) {
|
|
1444
|
+
logger.warn(`Invalid start date provided in dateRange: ${dateRange.start}`);
|
|
1445
|
+
}
|
|
1446
|
+
if ((dateRange === null || dateRange === void 0 ? void 0 : dateRange.end) && (!dateRange.end || isNaN(dateRange.end.getTime()))) {
|
|
1447
|
+
logger.warn(`Invalid end date provided in dateRange: ${dateRange.end}`);
|
|
1448
|
+
}
|
|
1449
|
+
// Structured Input Logic
|
|
1450
|
+
const structure = inputStructure !== null && inputStructure !== void 0 ? inputStructure : 'none'; // Default to 'none' if not specified
|
|
1451
|
+
logger.info(`Processing structured input with structure "${structure}" in %s for date range: ${JSON.stringify(dateRange)}`, inputDirectory);
|
|
1452
|
+
// Determine if time should be parsed from filenames
|
|
1453
|
+
const shouldParseTime = (_ref = inputFilenameOptions === null || inputFilenameOptions === void 0 ? void 0 : inputFilenameOptions.includes('time')) !== null && _ref !== void 0 ? _ref : false;
|
|
1454
|
+
if (shouldParseTime) {
|
|
1455
|
+
logger.debug('Filename time parsing enabled based on inputFilenameOptions.');
|
|
1456
|
+
} else {
|
|
1457
|
+
logger.debug('Filename time parsing disabled; defaulting times to 00:00 UTC.');
|
|
1458
|
+
}
|
|
1459
|
+
const filePattern = getFilePattern(features, extensions || [], logger);
|
|
1460
|
+
logger.debug('Processing Structured Input with pattern %s from %s', filePattern, inputDirectory);
|
|
1461
|
+
await storage.forEachFileIn(inputDirectory, async (filePath)=>{
|
|
1462
|
+
const processed = await processStructuredFile(filePath, inputDirectory, structure, shouldParseTime, callback, filePattern, dateRange, logger);
|
|
1463
|
+
if (processed) {
|
|
1464
|
+
fileCount++;
|
|
1465
|
+
}
|
|
1466
|
+
}, {
|
|
1467
|
+
pattern: filePattern,
|
|
1468
|
+
limit,
|
|
1469
|
+
concurrency
|
|
1470
|
+
});
|
|
1471
|
+
return fileCount;
|
|
1472
|
+
};
|
|
1473
|
+
|
|
1474
|
+
// Process files with unstructured input pattern
|
|
1475
|
+
const process$1 = async (inputDirectory, recursive, extensions, limit, logger, callback, concurrency)=>{
|
|
1476
|
+
const storage = create$4({
|
|
1477
|
+
log: logger.debug
|
|
1478
|
+
});
|
|
1479
|
+
let fileCount = 0;
|
|
1480
|
+
let filePattern = `${recursive ? '**/' : ''}*`;
|
|
1481
|
+
if (extensions && extensions.length > 0) {
|
|
1482
|
+
// Ensure the pattern correctly handles extensions with or without recursion
|
|
1483
|
+
if (recursive) {
|
|
1484
|
+
filePattern = `**/*.{${extensions.join(',')}}`;
|
|
1485
|
+
} else {
|
|
1486
|
+
filePattern = `*.{${extensions.join(',')}}`;
|
|
1487
|
+
}
|
|
1488
|
+
logger.debug(`Applying extension filter: ${extensions.join(',')}`);
|
|
1489
|
+
} else if (!recursive) {
|
|
1490
|
+
// Non-recursive without extension filter: only files in the top directory
|
|
1491
|
+
filePattern = `*.*`; // Adjust if files without extensions need matching
|
|
1492
|
+
}
|
|
1493
|
+
logger.info('Processing unstructured files %s in %s with pattern %s', recursive ? 'recursively' : 'non-recursively', inputDirectory, filePattern);
|
|
1494
|
+
await storage.forEachFileIn(inputDirectory, async (file)=>{
|
|
1495
|
+
try {
|
|
1496
|
+
logger.debug('Processing file %s', file);
|
|
1497
|
+
// Call callback without date for unstructured input
|
|
1498
|
+
await callback(file); // Pass undefined for the date parameter
|
|
1499
|
+
fileCount++;
|
|
1500
|
+
} catch (error) {
|
|
1501
|
+
if (error instanceof Error) {
|
|
1502
|
+
logger.error('Error processing file %s: %s\n%s', file, error.message, error.stack);
|
|
1503
|
+
} else {
|
|
1504
|
+
logger.error('Error processing file %s: %s', file, error);
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
}, {
|
|
1508
|
+
pattern: filePattern,
|
|
1509
|
+
limit,
|
|
1510
|
+
concurrency
|
|
1511
|
+
});
|
|
1512
|
+
return fileCount;
|
|
1513
|
+
};
|
|
1514
|
+
|
|
1515
|
+
const process = async (config, features, logger, callback, { start, end } = {})=>{
|
|
1516
|
+
if (!features.includes('input')) {
|
|
1517
|
+
throw new Error('Input feature is not enabled, skipping input processing');
|
|
1518
|
+
}
|
|
1519
|
+
const concurrency = config.concurrency;
|
|
1520
|
+
if (!concurrency) {
|
|
1521
|
+
throw new Error('Concurrency is not configured');
|
|
1522
|
+
}
|
|
1523
|
+
const inputDirectory = config.inputDirectory;
|
|
1524
|
+
if (!inputDirectory) {
|
|
1525
|
+
throw new Error('Input directory is not configured');
|
|
1526
|
+
}
|
|
1527
|
+
let fileCount = 0;
|
|
1528
|
+
if (features.includes('structured-input')) {
|
|
1529
|
+
logger.debug('Processing Structured Input from %s with start date %s and end date %s', inputDirectory, start, end);
|
|
1530
|
+
if (!start || !end) {
|
|
1531
|
+
throw new Error('Start or end date are both required for structured input');
|
|
1532
|
+
} else {
|
|
1533
|
+
fileCount = await process$2(config.inputStructure, config.inputFilenameOptions, config.extensions, config.timezone, start, end, config.limit, features, logger, inputDirectory, callback, concurrency);
|
|
1534
|
+
}
|
|
1535
|
+
} else {
|
|
1536
|
+
// Original Unstructured Input Logic
|
|
1537
|
+
logger.debug('Processing Unstructured Input from %s', inputDirectory);
|
|
1538
|
+
if (start || end) {
|
|
1539
|
+
throw new Error('Start or end date is not allowed for unstructured input');
|
|
1540
|
+
}
|
|
1541
|
+
fileCount = await process$1(inputDirectory, config.recursive || false, config.extensions || [], config.limit, logger, callback, concurrency);
|
|
1542
|
+
}
|
|
1543
|
+
logger.info('Processed %d files matching criteria.', fileCount);
|
|
1544
|
+
};
|
|
1545
|
+
|
|
1546
|
+
const create$3 = (config, options)=>{
|
|
1547
|
+
return {
|
|
1548
|
+
process: (callback, { start, end } = {})=>process(config, options.features, options.logger, callback, {
|
|
1549
|
+
start,
|
|
1550
|
+
end
|
|
1551
|
+
})
|
|
1552
|
+
};
|
|
1553
|
+
};
|
|
1554
|
+
|
|
1555
|
+
const create$2 = (config, options)=>{
|
|
1556
|
+
const logger = options.logger;
|
|
1557
|
+
const timezone = (config === null || config === void 0 ? void 0 : config.timezone) || 'UTC';
|
|
1558
|
+
const dates = create$5({
|
|
1559
|
+
timezone
|
|
1560
|
+
});
|
|
1561
|
+
const storage = create$4({
|
|
1562
|
+
log: logger.debug
|
|
1563
|
+
});
|
|
1564
|
+
const { outputDirectory, outputStructure, outputFilenameOptions } = config;
|
|
1565
|
+
function formatDate(date, outputStructure) {
|
|
1566
|
+
if (!outputStructure) {
|
|
1567
|
+
throw new Error('Unable to Create Output: Output structure is not set');
|
|
1568
|
+
}
|
|
1569
|
+
switch(outputStructure){
|
|
1570
|
+
case 'none':
|
|
1571
|
+
return dates.format(date, DATE_FORMAT_YEAR_MONTH_DAY);
|
|
1572
|
+
case 'year':
|
|
1573
|
+
return dates.format(date, DATE_FORMAT_MONTH_DAY);
|
|
1574
|
+
case 'month':
|
|
1575
|
+
return dates.format(date, DATE_FORMAT_DAY);
|
|
1576
|
+
case 'day':
|
|
1577
|
+
throw new Error('Cannot use date in filename when output structure is "day"');
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
function sanitizeFilenameString(str) {
|
|
1581
|
+
// Replace any character that is not alphanumeric, hyphen, underscore, or dot with an underscore
|
|
1582
|
+
return str.replace(/[^a-zA-Z0-9\-_.]/g, '_')// Replace multiple consecutive underscores with a single underscore
|
|
1583
|
+
.replace(/_+/g, '_')// Remove leading and trailing underscores
|
|
1584
|
+
.replace(/^_+|_+$/g, '')// Ensure the string is not empty
|
|
1585
|
+
.replace(/^$/, 'untitled');
|
|
1586
|
+
}
|
|
1587
|
+
function constructFilename(date, type, hash, options = {}) {
|
|
1588
|
+
const parts = [];
|
|
1589
|
+
// Add date if requested
|
|
1590
|
+
if (outputFilenameOptions === null || outputFilenameOptions === void 0 ? void 0 : outputFilenameOptions.includes('date')) {
|
|
1591
|
+
const dateStr = formatDate(date, outputStructure);
|
|
1592
|
+
parts.push(dateStr);
|
|
1593
|
+
}
|
|
1594
|
+
// Add time if requested
|
|
1595
|
+
if (outputFilenameOptions === null || outputFilenameOptions === void 0 ? void 0 : outputFilenameOptions.includes('time')) {
|
|
1596
|
+
const dates = create$5({
|
|
1597
|
+
timezone
|
|
1598
|
+
});
|
|
1599
|
+
const timeStr = dates.format(date, 'HHmm');
|
|
1600
|
+
parts.push(timeStr);
|
|
1601
|
+
}
|
|
1602
|
+
// Add message ID
|
|
1603
|
+
parts.push(hash);
|
|
1604
|
+
parts.push(type);
|
|
1605
|
+
// Add subject if requested
|
|
1606
|
+
if (outputFilenameOptions === null || outputFilenameOptions === void 0 ? void 0 : outputFilenameOptions.includes('subject')) {
|
|
1607
|
+
// Sanitize the provided subject, defaulting to empty string if undefined/null
|
|
1608
|
+
parts.push(sanitizeFilenameString(options.subject || ''));
|
|
1609
|
+
}
|
|
1610
|
+
return parts.join('-');
|
|
1611
|
+
}
|
|
1612
|
+
function constructOutputDirectory(creationTime) {
|
|
1613
|
+
// Throw this error to ensure that we don't success if outputDirectory or outputStructure are not set
|
|
1614
|
+
if (!outputDirectory) {
|
|
1615
|
+
throw new Error('Unable to Create Output: Output directory is not set');
|
|
1616
|
+
}
|
|
1617
|
+
if (!outputStructure) {
|
|
1618
|
+
throw new Error('Unable to Create Output: Output structure is not set');
|
|
1619
|
+
}
|
|
1620
|
+
const date = dates.date(creationTime);
|
|
1621
|
+
const year = dates.format(date, DATE_FORMAT_YEAR);
|
|
1622
|
+
const month = dates.format(date, DATE_FORMAT_MONTH);
|
|
1623
|
+
const day = dates.format(date, DATE_FORMAT_DAY);
|
|
1624
|
+
let outputPath;
|
|
1625
|
+
switch(outputStructure){
|
|
1626
|
+
case 'year':
|
|
1627
|
+
outputPath = path__namespace.join(outputDirectory, year);
|
|
1628
|
+
break;
|
|
1629
|
+
case 'month':
|
|
1630
|
+
outputPath = path__namespace.join(outputDirectory, year, month);
|
|
1631
|
+
break;
|
|
1632
|
+
case 'day':
|
|
1633
|
+
outputPath = path__namespace.join(outputDirectory, year, month, day);
|
|
1634
|
+
break;
|
|
1635
|
+
default:
|
|
1636
|
+
outputPath = outputDirectory;
|
|
1637
|
+
}
|
|
1638
|
+
storage.createDirectory(outputPath);
|
|
1639
|
+
return outputPath;
|
|
1640
|
+
}
|
|
1641
|
+
return {
|
|
1642
|
+
constructFilename,
|
|
1643
|
+
constructOutputDirectory
|
|
1644
|
+
};
|
|
1645
|
+
};
|
|
1646
|
+
|
|
1647
|
+
const create$1 = async (config, args, options)=>{
|
|
1648
|
+
const output = create$2(config, options);
|
|
1649
|
+
const input = create$3(config, options);
|
|
1650
|
+
const constructFilename = async (createDate, type, hash, context)=>{
|
|
1651
|
+
if (!options.features.includes('output')) {
|
|
1652
|
+
throw new Error('Output feature is not enabled, skipping output construction');
|
|
1653
|
+
}
|
|
1654
|
+
return output.constructFilename(createDate, type, hash, context);
|
|
1655
|
+
};
|
|
1656
|
+
const constructOutputDirectory = async (createDate)=>{
|
|
1657
|
+
if (!options.features.includes('output')) {
|
|
1658
|
+
throw new Error('Output feature is not enabled, skipping output construction');
|
|
1659
|
+
}
|
|
1660
|
+
return output.constructOutputDirectory(createDate);
|
|
1661
|
+
};
|
|
1662
|
+
return {
|
|
1663
|
+
process: input.process,
|
|
1664
|
+
constructFilename,
|
|
1665
|
+
constructOutputDirectory
|
|
1666
|
+
};
|
|
1667
|
+
};
|
|
1668
|
+
|
|
1669
|
+
const wrapLogger = (toWrap)=>{
|
|
1670
|
+
const log = (level, message, ...args)=>{
|
|
1671
|
+
message = `[${PROGRAM_NAME}] ${message}`;
|
|
1672
|
+
toWrap[level](message, ...args);
|
|
1673
|
+
};
|
|
1674
|
+
return {
|
|
1675
|
+
debug: (message, ...args)=>log('debug', message, ...args),
|
|
1676
|
+
info: (message, ...args)=>log('info', message, ...args),
|
|
1677
|
+
warn: (message, ...args)=>log('warn', message, ...args),
|
|
1678
|
+
error: (message, ...args)=>log('error', message, ...args),
|
|
1679
|
+
verbose: (message, ...args)=>log('verbose', message, ...args),
|
|
1680
|
+
silly: (message, ...args)=>log('silly', message, ...args)
|
|
1681
|
+
};
|
|
1682
|
+
};
|
|
1683
|
+
|
|
1684
|
+
const FilenameOptionSchema = zod.z.enum([
|
|
1685
|
+
'date',
|
|
1686
|
+
'time',
|
|
1687
|
+
'subject'
|
|
1688
|
+
]);
|
|
1689
|
+
const FilesystemStructureSchema = zod.z.enum([
|
|
1690
|
+
'none',
|
|
1691
|
+
'year',
|
|
1692
|
+
'month',
|
|
1693
|
+
'day'
|
|
1694
|
+
]);
|
|
1695
|
+
const DEFAULT_APP_OPTIONS = {
|
|
1696
|
+
timezone: DEFAULT_TIMEZONE,
|
|
1697
|
+
recursive: DEFAULT_RECURSIVE,
|
|
1698
|
+
inputDirectory: DEFAULT_INPUT_DIRECTORY,
|
|
1699
|
+
inputStructure: DEFAULT_INPUT_STRUCTURE,
|
|
1700
|
+
inputFilenameOptions: DEFAULT_INPUT_FILENAME_OPTIONS,
|
|
1701
|
+
outputDirectory: DEFAULT_OUTPUT_DIRECTORY,
|
|
1702
|
+
outputStructure: DEFAULT_OUTPUT_STRUCTURE,
|
|
1703
|
+
outputFilenameOptions: DEFAULT_OUTPUT_FILENAME_OPTIONS,
|
|
1704
|
+
extensions: DEFAULT_EXTENSIONS,
|
|
1705
|
+
concurrency: DEFAULT_CONCURRENCY
|
|
1706
|
+
};
|
|
1707
|
+
const DEFAULT_ALLOWED_OPTIONS = {
|
|
1708
|
+
inputStructures: ALLOWED_INPUT_STRUCTURES,
|
|
1709
|
+
inputFilenameOptions: ALLOWED_INPUT_FILENAME_OPTIONS,
|
|
1710
|
+
outputStructures: ALLOWED_OUTPUT_STRUCTURES,
|
|
1711
|
+
outputFilenameOptions: ALLOWED_OUTPUT_FILENAME_OPTIONS,
|
|
1712
|
+
extensions: ALLOWED_EXTENSIONS
|
|
1713
|
+
};
|
|
1714
|
+
const DEFAULT_FEATURES = [
|
|
1715
|
+
'output',
|
|
1716
|
+
'structured-output',
|
|
1717
|
+
'input',
|
|
1718
|
+
'extensions'
|
|
1719
|
+
];
|
|
1720
|
+
const DEFAULT_LOGGER = {
|
|
1721
|
+
// eslint-disable-next-line no-console
|
|
1722
|
+
debug: (message, ...args)=>console.debug(message, ...args),
|
|
1723
|
+
// eslint-disable-next-line no-console
|
|
1724
|
+
info: (message, ...args)=>console.info(message, ...args),
|
|
1725
|
+
// eslint-disable-next-line no-console
|
|
1726
|
+
warn: (message, ...args)=>console.warn(message, ...args),
|
|
1727
|
+
// eslint-disable-next-line no-console
|
|
1728
|
+
error: (message, ...args)=>console.error(message, ...args),
|
|
1729
|
+
// eslint-disable-next-line no-console
|
|
1730
|
+
verbose: (message, ...args)=>console.log(message, ...args),
|
|
1731
|
+
// eslint-disable-next-line no-console
|
|
1732
|
+
silly: (message, ...args)=>console.log(message, ...args)
|
|
1733
|
+
};
|
|
1734
|
+
const DEFAULT_OPTIONS = {
|
|
1735
|
+
defaults: DEFAULT_APP_OPTIONS,
|
|
1736
|
+
allowed: DEFAULT_ALLOWED_OPTIONS,
|
|
1737
|
+
features: DEFAULT_FEATURES,
|
|
1738
|
+
addDefaults: true,
|
|
1739
|
+
logger: DEFAULT_LOGGER
|
|
1740
|
+
};
|
|
1741
|
+
const ConfigSchema = zod.z.object({
|
|
1742
|
+
timezone: zod.z.string(),
|
|
1743
|
+
inputDirectory: zod.z.string().optional(),
|
|
1744
|
+
inputStructure: FilesystemStructureSchema.optional(),
|
|
1745
|
+
inputFilenameOptions: zod.z.array(FilenameOptionSchema).optional(),
|
|
1746
|
+
recursive: zod.z.boolean().optional(),
|
|
1747
|
+
outputDirectory: zod.z.string().optional(),
|
|
1748
|
+
outputStructure: FilesystemStructureSchema.optional(),
|
|
1749
|
+
outputFilenameOptions: zod.z.array(FilenameOptionSchema).optional(),
|
|
1750
|
+
extensions: zod.z.array(zod.z.string()).optional(),
|
|
1751
|
+
limit: zod.z.number().optional(),
|
|
1752
|
+
concurrency: zod.z.number().optional()
|
|
1753
|
+
});
|
|
1754
|
+
const create = (creationOptsParam = {})=>{
|
|
1755
|
+
let args;
|
|
1756
|
+
const options = {
|
|
1757
|
+
defaults: {
|
|
1758
|
+
...DEFAULT_APP_OPTIONS,
|
|
1759
|
+
...creationOptsParam.defaults
|
|
1760
|
+
},
|
|
1761
|
+
allowed: {
|
|
1762
|
+
...DEFAULT_ALLOWED_OPTIONS,
|
|
1763
|
+
...creationOptsParam.allowed
|
|
1764
|
+
},
|
|
1765
|
+
features: creationOptsParam.features || DEFAULT_FEATURES,
|
|
1766
|
+
addDefaults: creationOptsParam.addDefaults === undefined ? DEFAULT_OPTIONS.addDefaults : creationOptsParam.addDefaults,
|
|
1767
|
+
logger: wrapLogger(creationOptsParam.logger || DEFAULT_OPTIONS.logger)
|
|
1768
|
+
};
|
|
1769
|
+
return {
|
|
1770
|
+
configure: async (command)=>configure(command, options.defaults || {}, options.addDefaults, options.features),
|
|
1771
|
+
setLogger: (logger)=>{
|
|
1772
|
+
options.logger = wrapLogger(logger);
|
|
1773
|
+
},
|
|
1774
|
+
read: async (pArgs)=>{
|
|
1775
|
+
args = pArgs;
|
|
1776
|
+
return read(args, options.features);
|
|
1777
|
+
},
|
|
1778
|
+
applyDefaults: (config)=>applyDefaults(config, options.features, options.defaults || {}),
|
|
1779
|
+
validate: async (config)=>validate(config, options),
|
|
1780
|
+
operate: async (config)=>create$1(config, args, options)
|
|
1781
|
+
};
|
|
1782
|
+
};
|
|
1783
|
+
|
|
1784
|
+
exports.ConfigSchema = ConfigSchema;
|
|
1785
|
+
exports.DEFAULT_ALLOWED_OPTIONS = DEFAULT_ALLOWED_OPTIONS;
|
|
1786
|
+
exports.DEFAULT_APP_OPTIONS = DEFAULT_APP_OPTIONS;
|
|
1787
|
+
exports.DEFAULT_FEATURES = DEFAULT_FEATURES;
|
|
1788
|
+
exports.DEFAULT_LOGGER = DEFAULT_LOGGER;
|
|
1789
|
+
exports.DEFAULT_OPTIONS = DEFAULT_OPTIONS;
|
|
1790
|
+
exports.FilenameOptionSchema = FilenameOptionSchema;
|
|
1791
|
+
exports.FilesystemStructureSchema = FilesystemStructureSchema;
|
|
1792
|
+
exports.create = create;
|
|
1793
|
+
//# sourceMappingURL=dreadcabinet.cjs.map
|