edf2csv 0.5.85 → 0.5.87

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/CHANGELOG.md CHANGED
@@ -3,6 +3,65 @@
3
3
  Notable changes to edf2csv. Versions follow [semantic versioning](https://semver.org); while the
4
4
  major version is 0, a minor bump may contain breaking changes.
5
5
 
6
+ ## 0.5.87
7
+
8
+ ### Fixed: `--info --stdout` described files the command never writes
9
+
10
+ ```
11
+ $ edf2csv mixed-rates.edf --info --stdout
12
+ Would write 1,155 rows, roughly 22.2 KB.
13
+ warning: Channels use 3 different sampling rates (256 Hz, 128 Hz, 1 Hz).
14
+ They are written to one file per rate so no channel is resampled.
15
+ ```
16
+
17
+ for a command that refuses to run, writes nothing, and names no file:
18
+
19
+ ```
20
+ $ edf2csv mixed-rates.edf --stdout
21
+ error: --stdout needs exactly one table, but this recording produces 3 ...
22
+ ```
23
+
24
+ `--info` exists to say what a conversion will do, and refusing is one of the things it does.
25
+ It was not passed `--stdout` at all, so the plan it described was a different command's.
26
+
27
+ The conversion's three `--stdout` guards are lifted into `stdoutRefusal` and `--info` asks the
28
+ same question, so there is one wording rather than two that can drift — the test asserts the
29
+ preview contains the refusal's own sentence. Reported as a warning rather than a refusal, for
30
+ the reason 0.5.51 gives about the destination guards: `--info` writes nothing, so a rule about
31
+ the output has no business stopping it from describing the recording, and being told the command
32
+ will not work is exactly what was asked. New diagnostic code `STDOUT_UNSUPPORTED`, documented on
33
+ all three pages.
34
+
35
+ `--info --stdout --json` is no longer refused either. That guard exists because a CSV and a
36
+ summary cannot share stdout; under `--info` there is no CSV, and the description *is* the JSON.
37
+ It was the one way a script could see this warning at all.
38
+
39
+ ## 0.5.86
40
+
41
+ ### Fixed: a file holding half a million samples was told no data was written
42
+
43
+ ```
44
+ $ edf2csv partial.edf --out out
45
+ error: The file contains a header but no complete data record.
46
+ The recording was probably interrupted before any data was written.
47
+ ```
48
+
49
+ The file was 606 KB, of which 589 KB is sample data — more than half a million readings, 60% of
50
+ one record. Data plainly was written.
51
+
52
+ That hint is right about one way to reach this error and wrong about the other. A record is the
53
+ unit the format is addressed in, so a file holding less than one has nothing convertible and the
54
+ error stands — but "less than one record" happens both when a recording is cut short and when a
55
+ header describes records larger than the ones actually written, and only the first is an
56
+ interrupted acquisition. The message carried no figures at all, so nothing in it could be
57
+ checked against the file, and the one number worth looking at — the declared record size — was
58
+ the one not said.
59
+
60
+ Both are there now, because the comparison between them is the whole diagnosis: "The file
61
+ contains 589824 bytes of data, which is less than the 983040 its header says one data record
62
+ takes", pointing at the samples-per-record fields. A file that really does hold nothing after
63
+ its header keeps the sentence that is true of it.
64
+
6
65
  ## 0.5.85
7
66
 
8
67
  ### Fixed: the byte estimate read low on a recording timed from before zero
package/dist/cli.js CHANGED
@@ -18,7 +18,7 @@ import process from 'node:process';
18
18
  import { EdfError } from './edf/errors.js';
19
19
  import { EdfFile } from './edf/reader.js';
20
20
  import { buildPlan, withoutFileRateWarning } from './convert/plan.js';
21
- import { ConversionError, USAGE_ERROR_CODES, convert, defaultOutputDir } from './convert/run.js';
21
+ import { ConversionError, USAGE_ERROR_CODES, convert, defaultOutputDir, stdoutRefusal, } from './convert/run.js';
22
22
  import { ChannelSelectionError } from './convert/channels.js';
23
23
  // Shared with the library so a bad option is the same error whichever way it arrived.
24
24
  import { OptionError } from './convert/options.js';
@@ -256,7 +256,17 @@ export async function main(argv) {
256
256
  // Both of these claim stdout. Allowing them together wrote the CSV and then the summary
257
257
  // object onto one stream, producing a document that is neither valid CSV nor valid
258
258
  // JSON — and silently, since each half looked right on its own.
259
- if (toStdout && asJson) {
259
+ /*
260
+ Not under --info, which writes no CSV for --json to collide with.
261
+
262
+ The two claim stdout because one puts a CSV there and the other a summary. `--info` puts
263
+ neither: it prints a description, and under --json that description *is* the JSON. So
264
+ `--info --stdout --json` — a script asking "would --stdout work on this recording, in a
265
+ form I can parse" — was refused for a conflict that cannot arise, which is the same shape
266
+ as the destination guards 0.5.51 stopped applying to it. It is also the only way to see
267
+ the STDOUT_UNSUPPORTED warning from a script.
268
+ */
269
+ if (toStdout && asJson && values['info'] !== true) {
260
270
  /*
261
271
  `error: ` and the seven-space continuation, like every other refusal.
262
272
 
@@ -409,7 +419,7 @@ export async function main(argv) {
409
419
  if (batch && !asJson && index > 0)
410
420
  process.stdout.write('\n');
411
421
  try {
412
- warnings += await showInfo(input, shared, asJson, jsonIndent, batch);
422
+ warnings += await showInfo(input, shared, asJson, jsonIndent, batch, values['stdout'] === true);
413
423
  }
414
424
  catch (error) {
415
425
  failures.push(reportError(error, batch ? input : undefined));
@@ -618,7 +628,7 @@ export async function main(argv) {
618
628
  }
619
629
  }
620
630
  /** Print one recording's `--info`, and return how many diagnostics it raised. */
621
- async function showInfo(input, shared, asJson, jsonIndent, batch = false) {
631
+ async function showInfo(input, shared, asJson, jsonIndent, batch = false, toStdout = false) {
622
632
  const file = await EdfFile.open(input);
623
633
  try {
624
634
  /*
@@ -664,6 +674,30 @@ async function showInfo(input, shared, asJson, jsonIndent, batch = false) {
664
674
  recordStarts: timing.starts,
665
675
  }, shared);
666
676
  plan.diagnostics.push(...timing.diagnostics);
677
+ /*
678
+ What --stdout would do with this recording, which --info did not ask.
679
+
680
+ `--info --stdout` on a three-rate file predicted "Would write 1,155 rows, roughly
681
+ 22.2 KB" and said the channels "are written to one file per rate" — for a command that
682
+ refuses to run, writes nothing and names no file. --info exists to say what a
683
+ conversion will do, and refusing is one of the things it does.
684
+
685
+ A warning rather than a refusal, for the reason 0.5.51 gives about the destination
686
+ guards: --info writes nothing, so a rule about the output has no business stopping it
687
+ from describing the recording — and being told the command will not work is exactly
688
+ what was asked. The conversion's own guard supplies the words, so there is one wording.
689
+ */
690
+ if (toStdout) {
691
+ const refusal = stdoutRefusal(file, plan);
692
+ if (refusal) {
693
+ plan.diagnostics.push({
694
+ code: 'STDOUT_UNSUPPORTED',
695
+ severity: 'warning',
696
+ message: `--stdout would refuse this recording: ${refusal.message.replace(/^--stdout /u, '')}`,
697
+ ...(refusal.hint === undefined ? {} : { hint: refusal.hint }),
698
+ });
699
+ }
700
+ }
667
701
  process.stdout.write(asJson ? `${infoJson(file, plan, jsonIndent)}\n` : `${formatInfo(file, plan)}\n`);
668
702
  // Under --json the warnings travel inside the document, exactly as they do for a
669
703
  // conversion, so stderr stays empty and the whole result is one parseable thing.