edfcore 0.6.117 → 0.6.119

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.
@@ -109,5 +109,5 @@ export declare const SIGNAL_FIELD_BLOCK_OFFSETS: {
109
109
  readonly reserved: 224;
110
110
  };
111
111
  /** Published package version. Kept in sync with package.json by a test. */
112
- export declare const VERSION = "0.6.117";
112
+ export declare const VERSION = "0.6.119";
113
113
  //# sourceMappingURL=constants.d.ts.map
package/dist/constants.js CHANGED
@@ -79,5 +79,5 @@ export const SIGNAL_FIELD_BLOCK_OFFSETS = {
79
79
  reserved: 224,
80
80
  };
81
81
  /** Published package version. Kept in sync with package.json by a test. */
82
- export const VERSION = '0.6.117';
82
+ export const VERSION = '0.6.119';
83
83
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAe,eAAe,EAAE,MAAM,YAAY,CAAC;AAKpG;;;;;;;GAOG;AACH,wBAAuB,aAAa,CAClC,SAAS,EAAE,YAAY,EACvB,SAAS,EAAE,eAAe,EAC1B,OAAO,CAAC,EAAE,WAAW,GACpB,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,CAuF3C"}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAe,eAAe,EAAE,MAAM,YAAY,CAAC;AAKpG;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,YAAY,EACvB,SAAS,EAAE,eAAe,EAC1B,OAAO,CAAC,EAAE,WAAW,GACpB,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,CA+C3C"}
package/dist/stream.js CHANGED
@@ -26,7 +26,22 @@ const DEFAULT_STREAM_RECORDS = 256;
26
26
  * because the record is the only unit every signal in an EDF file shares — signals may sample at
27
27
  * different rates, so "a second of data" is a different number of samples per channel.
28
28
  */
29
- export async function* streamRecords(recording, selection, options) {
29
+ export function streamRecords(recording, selection, options) {
30
+ /*
31
+ * A plain function that validates and RETURNS a generator, rather than a generator function.
32
+ *
33
+ * The body of an `async function*` does not run until the first `next()`, so every check below
34
+ * was deferred to the first `for await` — and `streamRecords(recording)` with no selection at all
35
+ * returned an object, successfully. The comment further down makes this exact argument about
36
+ * `resolveSignals`: "Every other selection error in the package surfaces on the spot; this one
37
+ * waited for data." It waited for iteration too, which is worse, because a caller who builds the
38
+ * stream in one place and consumes it in another gets the refusal in the second.
39
+ *
40
+ * Everything answerable from the arguments now is: the recording, the selection, the chunk size,
41
+ * the signal indices, and the window itself — `resolveTimeWindow` is pure over the timeline and
42
+ * the index, and its refusal for a probed index over a discontinuous file is about the call, not
43
+ * about any byte (fixed in 0.6.118).
44
+ */
30
45
  assertRecording(recording, 'streamRecords');
31
46
  assertSelection(selection, 'streamRecords', '{ signalIndices, startSeconds, durationSeconds } and optionally chunkRecords');
32
47
  const chunkRecords = selection.chunkRecords ?? DEFAULT_STREAM_RECORDS;
@@ -43,6 +58,10 @@ export async function* streamRecords(recording, selection, options) {
43
58
  // Every other selection error in the package surfaces on the spot; this one waited for data.
44
59
  resolveSignals(recording.header, selection.signalIndices);
45
60
  const ranges = resolveTimeWindow(recording.timeline, recording.index, selection.startSeconds, selection.durationSeconds);
61
+ return streamRanges(recording, selection, ranges, chunkRecords, options);
62
+ }
63
+ /** The iteration itself, reached only once every argument above has been accepted. */
64
+ async function* streamRanges(recording, selection, ranges, chunkRecords, options) {
46
65
  const recordDurationTicks = recording.header.recordDurationTicks;
47
66
  for (const run of ranges) {
48
67
  let scanned = 0;
@@ -1 +1 @@
1
- {"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD,uEAAuE;AACvE,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAEnC;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,aAAa,CAClC,SAAuB,EACvB,SAA0B,EAC1B,OAAqB;IAErB,eAAe,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IAC5C,eAAe,CACb,SAAS,EACT,eAAe,EACf,8EAA8E,CAC/E,CAAC;IACF,MAAM,YAAY,GAAG,SAAS,CAAC,YAAY,IAAI,sBAAsB,CAAC;IACtE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,UAAU,CAClB,0EAA0E;YACxE,GAAG,aAAa,CAAC,YAAY,CAAC,IAAI;YAClC,mFAAmF,CACtF,CAAC;IACJ,CAAC;IAED,+FAA+F;IAC/F,+FAA+F;IAC/F,2FAA2F;IAC3F,sFAAsF;IACtF,6FAA6F;IAC7F,6FAA6F;IAC7F,cAAc,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,aAAa,CAAC,CAAC;IAE1D,MAAM,MAAM,GAAG,iBAAiB,CAC9B,SAAS,CAAC,QAAQ,EAClB,SAAS,CAAC,KAAK,EACf,SAAS,CAAC,YAAY,EACtB,SAAS,CAAC,eAAe,CAC1B,CAAC;IAEF,MAAM,mBAAmB,GAAG,SAAS,CAAC,MAAM,CAAC,mBAAmB,CAAC;IAEjE,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,8FAA8F;QAC9F,6FAA6F;QAC7F,IAAI,cAAuE,CAAC;QAE5E,OAAO,OAAO,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAgB;gBAC3B,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,OAAO;gBAC1B,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,KAAK,GAAG,OAAO,CAAC;aACnD,CAAC;YACF,0FAA0F;YAC1F,4FAA4F;YAC5F,MAAM,KAAK,GAAG,MAAM,WAAW,CAC7B,SAAS,EACT,EAAE,aAAa,EAAE,SAAS,CAAC,aAAa,EAAE,OAAO,EAAE,EACnD,OAAO,CACR,CAAC;YAEF;;;;;;;;;;;;;;;;;;;eAmBG;YACH,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;gBACjC,qBAAqB,CAAC,cAAc,EAAE;oBACpC,WAAW,EAAE,OAAO,CAAC,KAAK;oBAC1B,UAAU,EAAE,KAAK,CAAC,UAAU;iBAC7B,CAAC,CAAC;YACL,CAAC;YACD,cAAc,GAAG;gBACf,WAAW,EAAE,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,GAAG,CAAC;gBAC9C,UAAU,EAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,aAAa,GAAG,mBAAmB;aACzE,CAAC;YAEF,MAAM,KAAK,CAAC;YACZ,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC;QAC3B,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD,uEAAuE;AACvE,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAEnC;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,SAAuB,EACvB,SAA0B,EAC1B,OAAqB;IAErB;;;;;;;;;;;;;;OAcG;IACH,eAAe,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IAC5C,eAAe,CACb,SAAS,EACT,eAAe,EACf,8EAA8E,CAC/E,CAAC;IACF,MAAM,YAAY,GAAG,SAAS,CAAC,YAAY,IAAI,sBAAsB,CAAC;IACtE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,UAAU,CAClB,0EAA0E;YACxE,GAAG,aAAa,CAAC,YAAY,CAAC,IAAI;YAClC,mFAAmF,CACtF,CAAC;IACJ,CAAC;IAED,+FAA+F;IAC/F,+FAA+F;IAC/F,2FAA2F;IAC3F,sFAAsF;IACtF,6FAA6F;IAC7F,6FAA6F;IAC7F,cAAc,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,aAAa,CAAC,CAAC;IAE1D,MAAM,MAAM,GAAG,iBAAiB,CAC9B,SAAS,CAAC,QAAQ,EAClB,SAAS,CAAC,KAAK,EACf,SAAS,CAAC,YAAY,EACtB,SAAS,CAAC,eAAe,CAC1B,CAAC;IAEF,OAAO,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;AAC3E,CAAC;AAED,sFAAsF;AACtF,KAAK,SAAS,CAAC,CAAC,YAAY,CAC1B,SAAuB,EACvB,SAA0B,EAC1B,MAA8B,EAC9B,YAAoB,EACpB,OAAgC;IAEhC,MAAM,mBAAmB,GAAG,SAAS,CAAC,MAAM,CAAC,mBAAmB,CAAC;IAEjE,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,8FAA8F;QAC9F,6FAA6F;QAC7F,IAAI,cAAuE,CAAC;QAE5E,OAAO,OAAO,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAgB;gBAC3B,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,OAAO;gBAC1B,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,KAAK,GAAG,OAAO,CAAC;aACnD,CAAC;YACF,0FAA0F;YAC1F,4FAA4F;YAC5F,MAAM,KAAK,GAAG,MAAM,WAAW,CAC7B,SAAS,EACT,EAAE,aAAa,EAAE,SAAS,CAAC,aAAa,EAAE,OAAO,EAAE,EACnD,OAAO,CACR,CAAC;YAEF;;;;;;;;;;;;;;;;;;;eAmBG;YACH,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;gBACjC,qBAAqB,CAAC,cAAc,EAAE;oBACpC,WAAW,EAAE,OAAO,CAAC,KAAK;oBAC1B,UAAU,EAAE,KAAK,CAAC,UAAU;iBAC7B,CAAC,CAAC;YACL,CAAC;YACD,cAAc,GAAG;gBACf,WAAW,EAAE,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,GAAG,CAAC;gBAC9C,UAAU,EAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,aAAa,GAAG,mBAAmB;aACzE,CAAC;YAEF,MAAM,KAAK,CAAC;YACZ,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC;QAC3B,CAAC;IACH,CAAC;AACH,CAAC"}
package/docs/CHANGELOG.md CHANGED
@@ -6,6 +6,34 @@ alone does not tell you whether you were affected.
6
6
  edfcore is pre-1.0. Patch releases have carried behaviour changes where the old behaviour was a
7
7
  defect; those are called out below.
8
8
 
9
+ ## 0.6.119
10
+
11
+ - **Fixed** the inspector rounding a small number away to `0`. `fmt` did `value.toFixed(digits)` and
12
+ then stripped trailing zeros, so anything below half the last digit kept became the string `"0"`.
13
+ - Zero is not a neutral answer at any of the five places the page uses it. A signal declared
14
+ `-0.001 … 0.001` rendered as `0 … 0`, which is `DEGENERATE_PHYSICAL_RANGE` — a diagnostic the same
15
+ page lists three sections further down, on a file that does not have it. A record duration of 0 is
16
+ the legal file whose records do not advance in time. A rate of 0 is not a rate, and `undefined` is
17
+ how that is said here.
18
+ - Below the rounding it now keeps two significant figures, so 0.0001 s, 0.0033 Hz and a millivolt
19
+ range print as themselves. A true zero — the one value that should read as one — still prints `0`.
20
+
21
+ ## 0.6.118
22
+
23
+ - **Fixed** `streamRecords` deferring every argument check to the first `for await`.
24
+ - The body of an `async function*` does not run until the first `next()`, so `streamRecords(recording)`
25
+ with no selection at all returned a generator, successfully. The function's own comment makes this
26
+ argument one level down, about `resolveSignals`: "Every other selection error in the package
27
+ surfaces on the spot; this one waited for data."
28
+ - Waiting for iteration is worse than waiting for data, because the two happen in different places. A
29
+ pipeline that builds the stream in one function and consumes it in another got the refusal in the
30
+ second, with the arguments it names nowhere in sight; a stream that was built and then dropped
31
+ never reported the mistake at all.
32
+ - It is a plain function that validates and returns a generator now. Everything answerable from the
33
+ arguments is answered at the call: the recording, the selection, `chunkRecords`, the signal
34
+ indices, and the window — `resolveTimeWindow` is pure over the timeline and the index, and its
35
+ refusal for a probed index over a discontinuous file is about the call rather than about any byte.
36
+
9
37
  ## 0.6.117
10
38
 
11
39
  - **Fixed** the two per-signal arguments the envelope module did not check, one in each direction.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edfcore",
3
- "version": "0.6.117",
3
+ "version": "0.6.119",
4
4
  "description": "Modern, typed, zero-dependency reader for EDF, EDF+, BDF and BDF+ biosignal files. Works in browsers and Node with true random access.",
5
5
  "keywords": [
6
6
  "edf",
package/src/constants.ts CHANGED
@@ -93,4 +93,4 @@ export const SIGNAL_FIELD_BLOCK_OFFSETS = {
93
93
  } as const;
94
94
 
95
95
  /** Published package version. Kept in sync with package.json by a test. */
96
- export const VERSION = '0.6.117';
96
+ export const VERSION = '0.6.119';
package/src/stream.ts CHANGED
@@ -30,11 +30,26 @@ const DEFAULT_STREAM_RECORDS = 256;
30
30
  * because the record is the only unit every signal in an EDF file shares — signals may sample at
31
31
  * different rates, so "a second of data" is a different number of samples per channel.
32
32
  */
33
- export async function* streamRecords(
33
+ export function streamRecords(
34
34
  recording: EdfRecording,
35
35
  selection: StreamSelection,
36
36
  options?: ReadOptions,
37
37
  ): AsyncGenerator<EdfChunk, void, undefined> {
38
+ /*
39
+ * A plain function that validates and RETURNS a generator, rather than a generator function.
40
+ *
41
+ * The body of an `async function*` does not run until the first `next()`, so every check below
42
+ * was deferred to the first `for await` — and `streamRecords(recording)` with no selection at all
43
+ * returned an object, successfully. The comment further down makes this exact argument about
44
+ * `resolveSignals`: "Every other selection error in the package surfaces on the spot; this one
45
+ * waited for data." It waited for iteration too, which is worse, because a caller who builds the
46
+ * stream in one place and consumes it in another gets the refusal in the second.
47
+ *
48
+ * Everything answerable from the arguments now is: the recording, the selection, the chunk size,
49
+ * the signal indices, and the window itself — `resolveTimeWindow` is pure over the timeline and
50
+ * the index, and its refusal for a probed index over a discontinuous file is about the call, not
51
+ * about any byte (fixed in 0.6.118).
52
+ */
38
53
  assertRecording(recording, 'streamRecords');
39
54
  assertSelection(
40
55
  selection,
@@ -65,6 +80,17 @@ export async function* streamRecords(
65
80
  selection.durationSeconds,
66
81
  );
67
82
 
83
+ return streamRanges(recording, selection, ranges, chunkRecords, options);
84
+ }
85
+
86
+ /** The iteration itself, reached only once every argument above has been accepted. */
87
+ async function* streamRanges(
88
+ recording: EdfRecording,
89
+ selection: StreamSelection,
90
+ ranges: readonly RecordRange[],
91
+ chunkRecords: number,
92
+ options: ReadOptions | undefined,
93
+ ): AsyncGenerator<EdfChunk, void, undefined> {
68
94
  const recordDurationTicks = recording.header.recordDurationTicks;
69
95
 
70
96
  for (const run of ranges) {