edf2csv 0.7.257 → 0.7.258

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.
@@ -78,6 +78,15 @@ export interface ConvertResult {
78
78
  }
79
79
  export declare function convert(inputPath: string, options?: ConvertOptions): Promise<ConvertResult>;
80
80
  export declare function defaultOutputDir(inputPath: string): string;
81
+ /**
82
+ * Turn a Node filesystem error into something a person can act on: an errno as a sentence,
83
+ * so Node's own text never reaches the screen.
84
+ *
85
+ * Exported for the CLI's last-resort stdout listener, which is the third and last place a
86
+ * write failure becomes a message and the one that was still printing `ENOSPC: no space left
87
+ * on device, write`.
88
+ */
89
+ export declare function describeFsError(cause: unknown): string;
81
90
  /**
82
91
  * What the durations in the events that will actually be written look like.
83
92
  *
@@ -341,8 +341,15 @@ async function prepareOutputDir(dir, force) {
341
341
  }
342
342
  }
343
343
  }
344
- /** Turn a Node filesystem error into something a person can act on. */
345
- function describeFsError(cause) {
344
+ /**
345
+ * Turn a Node filesystem error into something a person can act on: an errno as a sentence,
346
+ * so Node's own text never reaches the screen.
347
+ *
348
+ * Exported for the CLI's last-resort stdout listener, which is the third and last place a
349
+ * write failure becomes a message and the one that was still printing `ENOSPC: no space left
350
+ * on device, write`.
351
+ */
352
+ export function describeFsError(cause) {
346
353
  const code = cause?.code;
347
354
  if (code === 'EACCES' || code === 'EPERM')
348
355
  return 'permission denied';
@@ -357,6 +364,20 @@ function describeFsError(cause) {
357
364
  return 'the filesystem is read-only';
358
365
  if (code === 'ENAMETOOLONG')
359
366
  return 'the path is too long';
367
+ /*
368
+ The two `writeHint` knew and this did not, which showed once the write failures started
369
+ coming through here: `writeHint` reads the same errno off the same error and has a
370
+ sentence for eleven of them, this had seven, and the gap was the two that only a write
371
+ reaches. `EISDIR` is a directory sitting where an output file belongs, which is the
372
+ commonest way to make one of these happen on purpose.
373
+
374
+ `EPIPE` is deliberately not here. The writer treats a reader hanging up as the ordinary
375
+ end of a pipeline rather than as a failure, so it never becomes a message.
376
+ */
377
+ if (code === 'EISDIR')
378
+ return 'a directory is sitting there already';
379
+ if (code === 'EMFILE' || code === 'ENFILE')
380
+ return 'too many files are open';
360
381
  /*
361
382
  The one this list could not describe, and the recursive mkdir above is what makes it
362
383
  surprising: every parent is created on the way, so "no such file or directory" is not a
@@ -530,8 +551,24 @@ async function writeSignalFiles(file, plan, outputDir, recordStarts, options, on
530
551
  throw new ConversionError('INPUT_UNREADABLE', cause.message, `${cause.hint ? `${cause.hint} ` : ''}What was written to ${where} before it failed is ` +
531
552
  `incomplete and should not be used.`);
532
553
  }
533
- const detail = cause instanceof Error ? cause.message : String(cause);
534
- throw new ConversionError('WRITE_FAILED', `Writing to ${outputDir === null ? 'stdout' : `"${outputDir}"`} failed: ${detail}`, writeHint(cause, outputDir === null));
554
+ /*
555
+ Through `describeFsError`, like the destination errors above, and not through Node's
556
+ own text.
557
+
558
+ That function exists to keep an errno and the internal call that raised it off the
559
+ screen — its comment says so in as many words, quoting the leak it was written for:
560
+ `Cannot create "dangle/x": ENOENT: no such file or directory, mkdir 'dangle'.` The
561
+ write failures never joined it, so a directory sitting where signals.csv belongs read
562
+
563
+ error: Writing to "out" failed: EISDIR: illegal operation on a directory, open 'out/signals.csv'
564
+
565
+ with the errno token, the syscall, the path repeated, and no full stop — the one
566
+ diagnostic shape this tool went back and fixed. The hint printed directly under it has
567
+ always read the same errno and said "A directory is sitting where that file belongs",
568
+ so the answer was in hand; it was the sentence above it that had not asked.
569
+ */
570
+ throw new ConversionError('WRITE_FAILED', `Writing to ${outputDir === null ? 'stdout' : `"${outputDir}"`} failed: ` +
571
+ `${describeFsError(cause)}.`, writeHint(cause, outputDir === null));
535
572
  }
536
573
  }
537
574
  /**
@@ -893,8 +930,8 @@ async function writeOutputFile(outputDir, name, contents, gzip = false, bom = fa
893
930
  await writeFile(path.join(outputDir, name), gzip ? gzipSync(contents) : contents, gzip ? undefined : 'utf8');
894
931
  }
895
932
  catch (cause) {
896
- const detail = cause instanceof Error ? cause.message : String(cause);
897
- throw new ConversionError('WRITE_FAILED', `Writing "${name}" to "${outputDir}" failed: ${detail}`, writeHint(cause));
933
+ // The same as the signal tables above; see the note there.
934
+ throw new ConversionError('WRITE_FAILED', `Writing "${name}" to "${outputDir}" failed: ${describeFsError(cause)}.`, writeHint(cause));
898
935
  }
899
936
  }
900
937
  async function writeChannelsCsv(outputDir, file, plan, gzip, bom) {