@engine9-io/input-tools 1.9.11 → 2.0.1

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/file/tools.js CHANGED
@@ -1,22 +1,22 @@
1
- const fs = require('node:fs');
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import debug$0 from 'debug';
4
+ import os from 'node:os';
5
+ import { mkdirp } from 'mkdirp';
6
+ import nodestream from 'node:stream';
7
+ import JSON5 from 'json5';
8
+ import unzipper from 'unzipper';
9
+ import dayjs from 'dayjs';
10
+ import clientS3 from '@aws-sdk/client-s3';
11
+ import { v7 as uuidv7 } from 'uuid';
2
12
 
3
13
  const fsp = fs.promises;
4
- const path = require('node:path');
5
- const debug = require('debug')('@engine9/input-tools');
6
- const os = require('node:os');
7
- const { mkdirp } = require('mkdirp');
8
- const { Transform } = require('node:stream');
14
+ const debug = debug$0('@engine9/input-tools');
9
15
 
10
- const JSON5 = require('json5');
11
- const { PassThrough } = require('node:stream');
12
- const progress = require('debug')('info:@engine9/input-tools');
13
- const unzipper = require('unzipper');
14
-
15
- const dayjs = require('dayjs');
16
-
17
- const { S3Client, HeadObjectCommand, GetObjectCommand } = require('@aws-sdk/client-s3');
18
-
19
- const { v7: uuidv7 } = require('uuid');
16
+ const { Transform } = nodestream;
17
+ const { PassThrough } = nodestream;
18
+ const progress = debug$0('info:@engine9/input-tools');
19
+ const { S3Client, HeadObjectCommand, GetObjectCommand } = clientS3;
20
20
 
21
21
  async function getTempDir({ accountId = 'engine9' }) {
22
22
  const dir = [os.tmpdir(), accountId, new Date().toISOString().substring(0, 10)].join(path.sep);
@@ -27,7 +27,6 @@ async function getTempDir({ accountId = 'engine9' }) {
27
27
  }
28
28
  return dir;
29
29
  }
30
-
31
30
  /*
32
31
  Get a new, timestamp based filename, creating any necessary directories
33
32
  options:
@@ -36,22 +35,18 @@ async function getTempDir({ accountId = 'engine9' }) {
36
35
  */
37
36
  async function getTempFilename(options) {
38
37
  let dir = await getTempDir(options);
39
-
40
38
  const target = options.targetFilename;
41
39
  if (target) {
42
40
  if (target.indexOf('/') === 0 || target.indexOf('\\') === 0) {
43
41
  // assume a full directory path has been specified
44
42
  return target;
45
43
  }
46
-
47
44
  // make a distinct directory, so we don't overwrite the file
48
45
  dir = `${dir}/${new Date()
49
46
  .toISOString()
50
47
  .slice(0, -6)
51
48
  .replace(/[^0-9]/g, '_')}`;
52
-
53
49
  const newDir = await mkdirp(dir);
54
-
55
50
  return `${newDir}/${target}`;
56
51
  }
57
52
  let { prefix } = options;
@@ -62,30 +57,23 @@ async function getTempFilename(options) {
62
57
  postfix = `_${options.source.split('/').pop()}`;
63
58
  postfix = postfix.replace(/['"\\]/g, '').replace(/[^a-zA-Z0-9_.-]/g, '_');
64
59
  }
65
-
66
60
  if (prefix) prefix += '_';
67
-
68
61
  const p = `${dir}/${prefix || ''}${uuidv7()}${postfix || '.txt'}`;
69
62
  return p;
70
63
  }
71
-
72
64
  async function writeTempFile(options) {
73
65
  const { content, postfix = '.txt' } = options;
74
66
  const filename = await getTempFilename({ ...options, postfix });
75
-
76
67
  await fsp.writeFile(filename, content);
77
68
  return { filename };
78
69
  }
79
-
80
70
  async function getPacketFiles({ packet }) {
81
71
  if (packet.indexOf('s3://') === 0) {
82
72
  const parts = packet.split('/');
83
73
  const Bucket = parts[2];
84
74
  const Key = parts.slice(3).join('/');
85
75
  const s3Client = new S3Client({});
86
-
87
76
  debug('Getting ', { Bucket, Key });
88
-
89
77
  // const directory = await unzipper.Open.s3(s3Client, { Bucket, Key });
90
78
  let size = null;
91
79
  const directory = await unzipper.Open.custom({
@@ -100,7 +88,6 @@ async function getPacketFiles({ packet }) {
100
88
  progress(`Retrieving file of size ${size / (1024 * 1024)} MB`);
101
89
  return info.ContentLength;
102
90
  },
103
-
104
91
  stream(offset, length) {
105
92
  const ptStream = new PassThrough();
106
93
  s3Client
@@ -117,17 +104,14 @@ async function getPacketFiles({ packet }) {
117
104
  .catch((error) => {
118
105
  ptStream.emit('error', error);
119
106
  });
120
-
121
107
  return ptStream;
122
108
  }
123
109
  });
124
-
125
110
  return directory;
126
111
  }
127
112
  const directory = await unzipper.Open.file(packet);
128
113
  return directory;
129
114
  }
130
-
131
115
  async function getManifest({ packet }) {
132
116
  if (!packet) throw new Error('no packet option specififed');
133
117
  const { files } = await getPacketFiles({ packet });
@@ -136,7 +120,6 @@ async function getManifest({ packet }) {
136
120
  const manifest = JSON.parse(content.toString());
137
121
  return manifest;
138
122
  }
139
-
140
123
  function getBatchTransform({ batchSize = 100 }) {
141
124
  return {
142
125
  transform: new Transform({
@@ -167,7 +150,6 @@ function getDebatchTransform() {
167
150
  })
168
151
  };
169
152
  }
170
-
171
153
  async function getFile({ filename, packet, type }) {
172
154
  if (!packet && !filename) throw new Error('no packet option specififed');
173
155
  let content = null;
@@ -196,7 +178,6 @@ async function getFile({ filename, packet, type }) {
196
178
  }
197
179
  return content;
198
180
  }
199
-
200
181
  async function streamPacket({ packet, type }) {
201
182
  if (!packet) throw new Error('no packet option specififed');
202
183
  const manifest = await getManifest({ packet });
@@ -208,11 +189,9 @@ async function streamPacket({ packet, type }) {
208
189
  const handle = files.find((d) => d.path === filePath);
209
190
  return { stream: handle.stream(), path: filePath };
210
191
  }
211
-
212
192
  async function downloadFile({ packet, type = 'person' }) {
213
193
  const { stream: fileStream, path: filePath } = await streamPacket({ packet, type });
214
194
  const filename = await getTempFilename({ targetFilename: filePath.split('/').pop() });
215
-
216
195
  return new Promise((resolve, reject) => {
217
196
  fileStream
218
197
  .pipe(fs.createWriteStream(filename))
@@ -222,13 +201,10 @@ async function downloadFile({ packet, type = 'person' }) {
222
201
  });
223
202
  });
224
203
  }
225
-
226
204
  function isValidDate(d) {
227
205
  // we WANT to use isNaN, not the Number.isNaN -- we're checking the date type
228
-
229
206
  return d instanceof Date && !isNaN(d);
230
207
  }
231
-
232
208
  function bool(x, _defaultVal) {
233
209
  const defaultVal = _defaultVal === undefined ? false : _defaultVal;
234
210
  if (x === undefined || x === null || x === '') return defaultVal;
@@ -241,7 +217,6 @@ function getStringArray(s, nonZeroLength) {
241
217
  let a = s || [];
242
218
  if (typeof a === 'number') a = String(a);
243
219
  if (typeof a === 'string') a = [a];
244
-
245
220
  if (typeof s === 'string') a = s.split(',');
246
221
  a = a.map((x) => x.toString().trim()).filter(Boolean);
247
222
  if (nonZeroLength && a.length === 0) a = [0];
@@ -252,21 +227,17 @@ function relativeDate(s, _initialDate) {
252
227
  if (!s || s === 'none') return null;
253
228
  if (typeof s.getMonth === 'function') return s;
254
229
  // We actually want a double equals here to test strings as well
255
-
256
230
  if (parseInt(s, 10) == s) {
257
231
  const r = new Date(parseInt(s, 10));
258
232
  if (!isValidDate(r)) throw new Error(`Invalid integer date:${s}`);
259
233
  return r;
260
234
  }
261
-
262
235
  if (initialDate) {
263
236
  initialDate = new Date(initialDate);
264
237
  } else {
265
238
  initialDate = new Date();
266
239
  }
267
-
268
240
  let r = s.match(/^([+-]{1})([0-9]+)([YyMwdhms]{1})([.a-z]*)$/);
269
-
270
241
  if (r) {
271
242
  let period = null;
272
243
  switch (r[3]) {
@@ -274,7 +245,6 @@ function relativeDate(s, _initialDate) {
274
245
  case 'y':
275
246
  period = 'years';
276
247
  break;
277
-
278
248
  case 'M':
279
249
  period = 'months';
280
250
  break;
@@ -297,9 +267,7 @@ function relativeDate(s, _initialDate) {
297
267
  period = 'minutes';
298
268
  break;
299
269
  }
300
-
301
270
  let d = dayjs(initialDate);
302
-
303
271
  if (r[1] === '+') {
304
272
  d = d.add(parseInt(r[2], 10), period);
305
273
  } else {
@@ -312,7 +280,6 @@ function relativeDate(s, _initialDate) {
312
280
  else if (opts[0] === 'end') d = d.endOf(opts[1] || 'day');
313
281
  else throw new Error(`Invalid relative date,unknown options:${r[4]}`);
314
282
  }
315
-
316
283
  return d.toDate();
317
284
  }
318
285
  if (s === 'now') {
@@ -323,7 +290,6 @@ function relativeDate(s, _initialDate) {
323
290
  if (!isValidDate(r)) throw new Error(`Invalid Date: ${s}`);
324
291
  return r;
325
292
  }
326
-
327
293
  /*
328
294
  When comparing two objects, some may come from a file (thus strings), and some from
329
295
  a database or elsewhere (not strings), so for deduping make sure to make them all strings
@@ -341,7 +307,6 @@ function appendPostfix(filename, postfix) {
341
307
  .split('.')
342
308
  .filter(Boolean)
343
309
  .filter((d) => d !== postfix);
344
-
345
310
  let targetFile = null;
346
311
  if (fileParts.slice(-1)[0] === 'gz') {
347
312
  targetFile = fileParts.slice(0, -2).concat(postfix).concat(fileParts.slice(-2)).join('.');
@@ -350,7 +315,6 @@ function appendPostfix(filename, postfix) {
350
315
  }
351
316
  return filenameParts.slice(0, -1).concat(targetFile).join('/');
352
317
  }
353
-
354
318
  function parseJSON5(o, defaultVal) {
355
319
  if (o) {
356
320
  if (typeof o === 'object') return o;
@@ -359,8 +323,23 @@ function parseJSON5(o, defaultVal) {
359
323
  }
360
324
  return defaultVal || o;
361
325
  }
362
-
363
- module.exports = {
326
+ export { appendPostfix };
327
+ export { bool };
328
+ export { downloadFile };
329
+ export { getTempFilename };
330
+ export { getTempDir };
331
+ export { getBatchTransform };
332
+ export { getDebatchTransform };
333
+ export { getFile };
334
+ export { getManifest };
335
+ export { getPacketFiles };
336
+ export { getStringArray };
337
+ export { makeStrings };
338
+ export { parseJSON5 };
339
+ export { relativeDate };
340
+ export { streamPacket };
341
+ export { writeTempFile };
342
+ export default {
364
343
  appendPostfix,
365
344
  bool,
366
345
  downloadFile,
package/index.js CHANGED
@@ -1,16 +1,16 @@
1
- const fs = require('node:fs');
2
-
3
- const path = require('node:path');
4
- const dayjs = require('dayjs');
5
-
6
- const debug = require('debug')('@engine9/input-tools');
7
-
8
- const unzipper = require('unzipper');
9
- const { v4: uuidv4, v5: uuidv5, v7: uuidv7, validate: uuidIsValid } = require('uuid');
10
- const archiver = require('archiver');
11
- const handlebars = require('handlebars');
12
-
13
- const FileUtilities = require('./file/FileUtilities');
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import dayjs from 'dayjs';
4
+ import debug$0 from 'debug';
5
+ import unzipper from 'unzipper';
6
+ import { v4 as uuidv4, v5 as uuidv5, v7 as uuidv7, validate as uuidIsValid } from 'uuid';
7
+ import archiver from 'archiver';
8
+ import handlebars from 'handlebars';
9
+ import FileUtilities from './file/FileUtilities.js';
10
+ import tools from './file/tools.js';
11
+ import ForEachEntry from './ForEachEntry.js';
12
+ import { TIMELINE_ENTRY_TYPES } from './timelineTypes.js';
13
+ const debug = debug$0('@engine9/input-tools');
14
14
 
15
15
  const {
16
16
  appendPostfix,
@@ -30,40 +30,28 @@ const {
30
30
  streamPacket,
31
31
  makeStrings,
32
32
  writeTempFile
33
- } = require('./file/tools');
34
-
35
- const ForEachEntry = require('./ForEachEntry');
36
-
37
- const { TIMELINE_ENTRY_TYPES } = require('./timelineTypes');
38
-
33
+ } = tools;
39
34
  function getFormattedDate(dateObject, format = 'MMM DD,YYYY') {
40
35
  let d = dateObject;
41
36
  if (d === 'now') d = new Date();
42
37
  if (d) return dayjs(d).format(format);
43
38
  return '';
44
39
  }
45
-
46
40
  handlebars.registerHelper('date', (d, f) => {
47
41
  let format;
48
42
  if (typeof f === 'string') format = f;
49
43
  return getFormattedDate(d, format);
50
44
  });
51
45
  handlebars.registerHelper('json', (d) => JSON.stringify(d));
52
-
53
46
  handlebars.registerHelper('uuid', () => uuidv7());
54
-
55
47
  handlebars.registerHelper('percent', (a, b) => `${((100 * a) / b).toFixed(2)}%`);
56
-
57
48
  handlebars.registerHelper('or', (a, b, c) => a || b || c);
58
-
59
49
  async function list(_path) {
60
50
  const directory = await unzipper.Open.file(_path);
61
-
62
51
  return new Promise((resolve, reject) => {
63
52
  directory.files[0].stream().pipe(fs.createWriteStream('firstFile')).on('error', reject).on('finish', resolve);
64
53
  });
65
54
  }
66
-
67
55
  async function extract(_path, _file) {
68
56
  const directory = await unzipper.Open(_path);
69
57
  // return directory.files.map((f) => f.path);
@@ -73,7 +61,6 @@ async function extract(_path, _file) {
73
61
  file.stream().pipe(fs.createWriteStream(tempFilename)).on('error', reject).on('finish', resolve);
74
62
  });
75
63
  }
76
-
77
64
  function appendFiles(existingFiles, _newFiles, options) {
78
65
  const newFiles = getStringArray(_newFiles);
79
66
  if (newFiles.length === 0) return;
@@ -82,7 +69,6 @@ function appendFiles(existingFiles, _newFiles, options) {
82
69
  if (!dateCreated) dateCreated = new Date().toISOString();
83
70
  let arr = newFiles;
84
71
  if (!Array.isArray(newFiles)) arr = [arr];
85
-
86
72
  arr.forEach((p) => {
87
73
  const item = {
88
74
  type,
@@ -90,13 +76,11 @@ function appendFiles(existingFiles, _newFiles, options) {
90
76
  isNew: true,
91
77
  dateCreated
92
78
  };
93
-
94
79
  if (typeof p === 'string') {
95
80
  item.originalFilename = path.resolve(process.cwd(), p);
96
81
  } else {
97
82
  item.originalFilename = path.resolve(process.cwd(), item.originalFilename);
98
83
  }
99
-
100
84
  const file = item.originalFilename.split(path.sep).pop();
101
85
  item.path = `${type}/${file}`;
102
86
  const existingFile = existingFiles.find((f) => f.path === item.path);
@@ -104,7 +88,6 @@ function appendFiles(existingFiles, _newFiles, options) {
104
88
  existingFiles.push(item);
105
89
  });
106
90
  }
107
-
108
91
  async function create(options) {
109
92
  const {
110
93
  accountId = 'engine9',
@@ -116,16 +99,13 @@ async function create(options) {
116
99
  statisticsFiles = [] // files with aggregate statistics
117
100
  } = options;
118
101
  if (options.peopleFiles) throw new Error('Unknown option: peopleFiles, did you mean personFiles?');
119
-
120
102
  const files = [];
121
103
  const dateCreated = new Date().toISOString();
122
104
  appendFiles(files, messageFiles, { type: 'message', dateCreated });
123
105
  appendFiles(files, personFiles, { type: 'person', dateCreated });
124
106
  appendFiles(files, timelineFiles, { type: 'timeline', dateCreated });
125
107
  appendFiles(files, statisticsFiles, { type: 'statistics', dateCreated });
126
-
127
108
  const zipFilename = target || (await getTempFilename({ postfix: '.packet.zip' }));
128
-
129
109
  const manifest = {
130
110
  accountId,
131
111
  source: {
@@ -134,7 +114,6 @@ async function create(options) {
134
114
  dateCreated,
135
115
  files
136
116
  };
137
-
138
117
  // create a file to stream archive data to.
139
118
  const output = fs.createWriteStream(zipFilename);
140
119
  const archive = archiver('zip', {
@@ -152,37 +131,30 @@ async function create(options) {
152
131
  bytes: archive.pointer()
153
132
  });
154
133
  });
155
-
156
134
  // This event is fired when the data source is drained no matter what was the data source.
157
135
  // It is not part of this library but rather from the NodeJS Stream API.
158
136
  // @see: https://nodejs.org/api/stream.html#stream_event_end
159
137
  output.on('end', () => {
160
138
  // debug('end event -- Data has been drained');
161
139
  });
162
-
163
140
  // warnings could be file not founds, etc, but we error even on those
164
141
  archive.on('warning', (err) => {
165
142
  reject(err);
166
143
  });
167
-
168
144
  // good practice to catch this error explicitly
169
145
  archive.on('error', (err) => {
170
146
  reject(err);
171
147
  });
172
-
173
148
  archive.pipe(output);
174
-
175
149
  files.forEach(({ path: name, originalFilename }) => archive.file(originalFilename, { name }));
176
150
  files.forEach((f) => {
177
151
  delete f.originalFilename;
178
152
  delete f.isNew;
179
153
  });
180
-
181
154
  archive.append(Buffer.from(JSON.stringify(manifest, null, 4), 'utf8'), { name: 'manifest.json' });
182
155
  archive.finalize();
183
156
  });
184
157
  }
185
-
186
158
  function intToByteArray(_v) {
187
159
  // we want to represent the input as a 8-bytes array
188
160
  const byteArray = [0, 0, 0, 0, 0, 0, 0, 0];
@@ -192,14 +164,12 @@ function intToByteArray(_v) {
192
164
  byteArray[index] = byte;
193
165
  v = (v - byte) / 256;
194
166
  }
195
-
196
167
  return byteArray;
197
168
  }
198
169
  function getPluginUUID(uniqueNamespaceLikeDomainName, valueWithinNamespace) {
199
170
  // Random custom namespace for plugins -- not secure, just a namespace:
200
171
  return uuidv5(`${uniqueNamespaceLikeDomainName}::${valueWithinNamespace}`, 'f9e1024d-21ac-473c-bac6-64796dd771dd');
201
172
  }
202
-
203
173
  function getInputUUID(a, b) {
204
174
  let pluginId = a;
205
175
  let remoteInputId = b;
@@ -207,7 +177,6 @@ function getInputUUID(a, b) {
207
177
  pluginId = a.pluginId;
208
178
  remoteInputId = a.remoteInputId;
209
179
  }
210
-
211
180
  if (!pluginId) throw new Error('getInputUUID: Cowardly rejecting a blank plugin_id');
212
181
  if (!uuidIsValid(pluginId)) throw new Error(`Invalid pluginId:${pluginId}, should be a UUID`);
213
182
  const rid = (remoteInputId || '').trim();
@@ -216,7 +185,6 @@ function getInputUUID(a, b) {
216
185
  // 3d0e5d99-6ba9-4fab-9bb2-c32304d3df8e
217
186
  return uuidv5(`${pluginId}:${rid}`, '3d0e5d99-6ba9-4fab-9bb2-c32304d3df8e');
218
187
  }
219
-
220
188
  const timestampMatch = /^\d{13}$/;
221
189
  function dateFromString(s) {
222
190
  if (typeof s === 'number') return new Date(s);
@@ -225,7 +193,6 @@ function dateFromString(s) {
225
193
  }
226
194
  return new Date(s);
227
195
  }
228
-
229
196
  function getUUIDv7(date, inputUuid) {
230
197
  /* optional date and input UUID */
231
198
  const uuid = inputUuid || uuidv7();
@@ -234,7 +201,6 @@ function getUUIDv7(date, inputUuid) {
234
201
  const d = dateFromString(date);
235
202
  // isNaN behaves differently than Number.isNaN -- we're actually going for the
236
203
  // attempted conversion here
237
-
238
204
  if (isNaN(d)) throw new Error(`getUUIDv7 got an invalid date:${date || '<blank>'}`);
239
205
  const dateBytes = intToByteArray(d.getTime()).reverse();
240
206
  dateBytes.slice(2, 8).forEach((b, i) => {
@@ -248,7 +214,6 @@ function getUUIDTimestamp(uuid) {
248
214
  const ts = parseInt(`${uuid}`.replace(/-/g, '').slice(0, 12), 16);
249
215
  return new Date(ts);
250
216
  }
251
-
252
217
  function getEntryTypeId(o, { defaults = {} } = {}) {
253
218
  let id = o.entry_type_id || defaults.entry_type_id;
254
219
  if (id) return id;
@@ -263,32 +228,27 @@ function getEntryTypeId(o, { defaults = {} } = {}) {
263
228
  function getEntryType(o, defaults = {}) {
264
229
  let etype = o.entry_type || defaults.entry_type;
265
230
  if (etype) return etype;
266
-
267
231
  const id = o.entry_type_id || defaults.entry_type_id;
268
-
269
232
  etype = TIMELINE_ENTRY_TYPES[id];
270
233
  if (etype === undefined) throw new Error(`Invalid entry_type: ${etype}`);
271
234
  return etype;
272
235
  }
273
-
274
236
  const requiredTimelineEntryFields = ['ts', 'entry_type_id', 'input_id', 'person_id'];
275
-
276
237
  function getTimelineEntryUUID(inputObject, { defaults = {} } = {}) {
277
238
  const o = { ...defaults, ...inputObject };
278
239
  /*
279
- Outside systems CAN specify a unique UUID as remote_entry_uuid,
280
- which will be used for updates, etc.
281
- If not, it will be generated using whatever info we have
282
- */
240
+ Outside systems CAN specify a unique UUID as remote_entry_uuid,
241
+ which will be used for updates, etc.
242
+ If not, it will be generated using whatever info we have
243
+ */
283
244
  if (o.remote_entry_uuid) {
284
245
  if (!uuidIsValid(o.remote_entry_uuid)) throw new Error('Invalid remote_entry_uuid, it must be a UUID');
285
246
  return o.remote_entry_uuid;
286
247
  }
287
248
  /*
288
- Outside systems CAN specify a unique remote_entry_id
289
- If not, it will be generated using whatever info we have
290
- */
291
-
249
+ Outside systems CAN specify a unique remote_entry_id
250
+ If not, it will be generated using whatever info we have
251
+ */
292
252
  if (o.remote_entry_id) {
293
253
  // get a temp ID
294
254
  if (!o.input_id)
@@ -300,17 +260,13 @@ function getTimelineEntryUUID(inputObject, { defaults = {} } = {}) {
300
260
  return getUUIDv7(o.ts, uuid);
301
261
  }
302
262
  o.entry_type_id = getEntryTypeId(o);
303
-
304
263
  const missing = requiredTimelineEntryFields.filter((d) => o[d] === undefined); // 0 could be an entry type value
305
-
306
264
  if (missing.length > 0) throw new Error(`Missing required fields to append an entry_id:${missing.join(',')}`);
307
265
  const ts = new Date(o.ts);
308
266
  // isNaN behaves differently than Number.isNaN -- we're actually going for the
309
267
  // attempted conversion here
310
-
311
268
  if (isNaN(ts)) throw new Error(`getTimelineEntryUUID got an invalid date:${o.ts || '<blank>'}`);
312
269
  const idString = `${ts.toISOString()}-${o.person_id}-${o.entry_type_id}-${o.source_code_id || 0}`;
313
-
314
270
  if (!uuidIsValid(o.input_id)) {
315
271
  throw new Error(`Invalid input_id:'${o.input_id}', type ${typeof o.input_id} -- should be a uuid`);
316
272
  }
@@ -321,13 +277,11 @@ function getTimelineEntryUUID(inputObject, { defaults = {} } = {}) {
321
277
  // may not match this standard, uuid sorting isn't guaranteed
322
278
  return getUUIDv7(ts, uuid);
323
279
  }
324
-
325
280
  function getDateRangeArray(startDate, endDate) {
326
281
  const start = new Date(startDate);
327
282
  const end = new Date(endDate);
328
283
  const result = [];
329
284
  const msInDay = 24 * 60 * 60 * 1000;
330
-
331
285
  function addDays(date, days) {
332
286
  const d = new Date(date);
333
287
  d.setDate(d.getDate() + days);
@@ -343,13 +297,10 @@ function getDateRangeArray(startDate, endDate) {
343
297
  d.setFullYear(d.getFullYear() + years);
344
298
  return d;
345
299
  }
346
-
347
300
  const diffDays = Math.floor((end - start) / msInDay);
348
301
  const diffMonths = (end.getFullYear() - start.getFullYear()) * 12 + (end.getMonth() - start.getMonth());
349
302
  const diffYears = end.getFullYear() - start.getFullYear();
350
-
351
303
  let current = new Date(start);
352
-
353
304
  let stepFn;
354
305
  if (diffDays < 10) {
355
306
  stepFn = (date) => addDays(date, 1);
@@ -364,7 +315,6 @@ function getDateRangeArray(startDate, endDate) {
364
315
  } else {
365
316
  stepFn = (date) => addYears(date, 1);
366
317
  }
367
-
368
318
  while (current <= end) {
369
319
  result.push(new Date(current));
370
320
  const next = stepFn(current);
@@ -377,7 +327,6 @@ function getDateRangeArray(startDate, endDate) {
377
327
  }
378
328
  return result;
379
329
  }
380
-
381
330
  class ObjectError extends Error {
382
331
  constructor(data) {
383
332
  if (typeof data === 'string') {
@@ -394,8 +343,44 @@ class ObjectError extends Error {
394
343
  }
395
344
  }
396
345
  }
397
-
398
- module.exports = {
346
+ export { appendPostfix };
347
+ export { bool };
348
+ export { create };
349
+ export { list };
350
+ export { downloadFile };
351
+ export { extract };
352
+ export { ForEachEntry };
353
+ export { FileUtilities };
354
+ export { getBatchTransform };
355
+ export { getDateRangeArray };
356
+ export { getDebatchTransform };
357
+ export { getEntryType };
358
+ export { getEntryTypeId };
359
+ export { getFile };
360
+ export { getManifest };
361
+ export { getStringArray };
362
+ export { getTempDir };
363
+ export { getTempFilename };
364
+ export { getTimelineEntryUUID };
365
+ export { getPacketFiles };
366
+ export { getPluginUUID };
367
+ export { getInputUUID };
368
+ export { getUUIDv7 };
369
+ export { getUUIDTimestamp };
370
+ export { handlebars };
371
+ export { isValidDate };
372
+ export { makeStrings };
373
+ export { ObjectError };
374
+ export { parseJSON5 };
375
+ export { relativeDate };
376
+ export { streamPacket };
377
+ export { TIMELINE_ENTRY_TYPES };
378
+ export { writeTempFile };
379
+ export { uuidIsValid };
380
+ export { uuidv4 };
381
+ export { uuidv5 };
382
+ export { uuidv7 };
383
+ export default {
399
384
  appendPostfix,
400
385
  bool,
401
386
  create,
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@engine9-io/input-tools",
3
- "version": "1.9.11",
3
+ "version": "2.0.1",
4
+ "type": "module",
4
5
  "description": "Tools for dealing with Engine9 inputs",
5
6
  "main": "index.js",
6
7
  "scripts": {
package/test/cli.js CHANGED
@@ -1,10 +1,9 @@
1
- const argv = require('yargs/yargs')(process.argv.slice(2)).parse();
2
- const methods = require('../index');
3
-
1
+ import yargs from 'yargs/yargs';
2
+ import methods from '../index.js';
3
+ const argv = yargs(process.argv.slice(2)).parse();
4
4
  async function run() {
5
5
  if (typeof methods[argv._[0]] !== 'function') throw new Error(`${argv._[0]} is not a function`);
6
6
  const output = await methods[argv._[0]](argv);
7
- // eslint-disable-next-line no-console
8
7
  console.log(output);
9
8
  }
10
9
  run();
package/test/file.js CHANGED
@@ -1,9 +1,9 @@
1
- const { it } = require('node:test');
2
- const assert = require('node:assert');
3
- const debug = require('debug')('files');
4
-
5
- const { FileUtilities } = require('../index');
6
-
1
+ import nodetest from 'node:test';
2
+ import assert from 'node:assert';
3
+ import * as debug$0 from 'debug';
4
+ import { FileUtilities } from '../index.js';
5
+ const { it } = nodetest;
6
+ const debug = debug$0('files');
7
7
  it('Should list a directory', async () => {
8
8
  const futil = new FileUtilities({ accountId: 'test' });
9
9
  let files = await futil.list({ directory: '.' });
@@ -14,7 +14,6 @@ it('Should list a directory', async () => {
14
14
  let endTest = await futil.list({ directory: '.', end: '1900-01-01' });
15
15
  assert(endTest.length === 0, 'Should NOT have any files before past end date');
16
16
  });
17
-
18
17
  it('Should be able to analyze CSV files with and without header lines', async () => {
19
18
  const futil = new FileUtilities({ accountId: 'test' });
20
19
  const f1 = await futil.columns({ filename: __dirname + '/sample/fileWithHead.csv' });