edf2csv 0.5.89 → 0.5.91

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,66 @@
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.91
7
+
8
+ ### Fixed: `--start` at the recording's exact length was accepted when the length was a product
9
+
10
+ `--start` at or past the end of a recording is an error, because the result would be an empty
11
+ file that looks like a successful conversion. The guard compares against
12
+ `recordCount * recordDuration` — and with a fractional record duration that product is not the
13
+ number it prints as. 6003 records of 0.1s is 600.3000000000001, so on a recording `--info`
14
+ calls "10m 0.3s":
15
+
16
+ ```
17
+ $ edf2csv tenmin.edf --start 600.3 --out out
18
+ warning: No samples fall inside the requested window (600.300s to 600.300s), so the signal
19
+ files hold their headers and no data.
20
+ $ echo $?
21
+ 0
22
+ ```
23
+
24
+ Exactly the empty conversion the error exists to prevent, and exactly what `--start 2` on a
25
+ two-second recording is refused for. Which of the two you get depends on whether your record
26
+ duration is a whole number.
27
+
28
+ Compared with a relative epsilon now — the same shape the long layout uses to decide two sample
29
+ times are one instant: well below any real sample interval, and well above the rounding that two
30
+ routes to one quantity produce. `--start 600.2` on the same file still converts its ten samples.
31
+
32
+ ## 0.5.90
33
+
34
+ ### Fixed: the duration warnings described rows a window had excluded
35
+
36
+ ```
37
+ $ edf2csv rec.edf --start 2 --end 3 --out out --strict
38
+ warning: 1 annotation states a duration below zero ... The value is written to annotations.csv as the file gave it ... check these rows before using the durations.
39
+ warning: 1 annotation states a duration that is not a number, so its duration_s cell is empty.
40
+ --strict: 2 warnings raised, so this run is reported as a failure.
41
+
42
+ $ cat out/annotations.csv
43
+ onset_s,duration_s,description,record_index
44
+ 2.5,0.25,clean event,2
45
+ ```
46
+
47
+ One row, with a populated, positive duration. There is no such value, no such cell and no such
48
+ rows — and `--strict` failed the run over two events it never wrote.
49
+
50
+ Both warnings are mine, from 0.5.55 and 0.5.58, and both were raised from the counts the
51
+ decoder accumulates over the whole file while `annotations.csv` is filtered to the requested
52
+ window. `--info` had the other half of it: on an EDF+D recording it printed "The value is
53
+ written to annotations.csv as the file gave it" while writing no files at all.
54
+
55
+ Counted from the events themselves now, after the same filter the writer applies, so the count
56
+ and the sentence describe the same rows. An unreadable duration is carried on the event as
57
+ `durationUnreadable`, because `duration: null` cannot say whether the file gave one — which is
58
+ the ambiguity those warnings exist to flag, and a library caller now has it too. A negative
59
+ duration needs no flag; the value is right there.
60
+
61
+ `--info` raises them against the window it was given, so it predicts what the conversion will
62
+ say rather than a different set. On a continuous EDF+ it still says nothing, because it does not
63
+ read the whole annotation channel — that is the documented limit of a header read, not a
64
+ regression.
65
+
6
66
  ## 0.5.89
7
67
 
8
68
  ### Fixed: the getting-started example asked for a channel the recording does not have
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, stdoutRefusal, } from './convert/run.js';
21
+ import { ConversionError, USAGE_ERROR_CODES, convert, defaultOutputDir, durationDiagnostics, 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';
@@ -687,6 +687,17 @@ async function showInfo(input, shared, asJson, jsonIndent, batch = false, toStdo
687
687
  from describing the recording — and being told the command will not work is exactly
688
688
  what was asked. The conversion's own guard supplies the words, so there is one wording.
689
689
  */
690
+ /*
691
+ What the conversion would say about the durations it would write.
692
+
693
+ Same window the conversion applies, so --info predicts the warnings rather than a
694
+ different set. Raised here rather than in the parser because the counts have to be of
695
+ the rows that reach annotations.csv — see durationDiagnostics.
696
+ */
697
+ plan.diagnostics.push(...durationDiagnostics(annotationData.annotations, {
698
+ from: plan.range.startSeconds,
699
+ to: plan.range.endSeconds,
700
+ }));
690
701
  if (toStdout) {
691
702
  const refusal = stdoutRefusal(file, plan);
692
703
  if (refusal) {