edfcore 0.2.20 → 0.2.21
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 +11 -0
- package/dist/annotations-query.d.ts.map +1 -1
- package/dist/annotations-query.js +4 -1
- package/dist/annotations-query.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/header/lookup.d.ts +16 -0
- package/dist/header/lookup.d.ts.map +1 -1
- package/dist/header/lookup.js +25 -1
- package/dist/header/lookup.js.map +1 -1
- package/package.json +1 -1
- package/src/annotations-query.ts +4 -1
- package/src/constants.ts +1 -1
- package/src/header/lookup.ts +26 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,17 @@ 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.2.21
|
|
10
|
+
|
|
11
|
+
- **Fixed** `matchSignals` and `filterAnnotationsByText` returning roughly half their matches when
|
|
12
|
+
the caller's `RegExp` carried a `g` or `y` flag. `RegExp.prototype.test` starts from `lastIndex`
|
|
13
|
+
and advances it with those flags, so across an array each element's answer depended on what the
|
|
14
|
+
previous one matched: four EEG channels and `/^EEG/g` gave back the first and the third. Even a
|
|
15
|
+
match-everything pattern stopped returning every signal once it carried the flag, and a second
|
|
16
|
+
call with the same regex object gave a different answer than the first. A `g` flag on a
|
|
17
|
+
membership test means nothing, so both now test against a clone with `lastIndex` reset — cloned
|
|
18
|
+
rather than reset in place, so a shared module-level regex is never mutated.
|
|
19
|
+
|
|
9
20
|
## 0.2.20
|
|
10
21
|
|
|
11
22
|
- **Fixed** `filterAnnotationsByTime` dropping an annotation whose duration was written as an
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"annotations-query.d.ts","sourceRoot":"","sources":["../src/annotations-query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;
|
|
1
|
+
{"version":3,"file":"annotations-query.d.ts","sourceRoot":"","sources":["../src/annotations-query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAErE;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,SAAS,aAAa,EAAE,EACrC,MAAM,EAAE,mBAAmB,GAC1B,SAAS,aAAa,EAAE,CAsB1B;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,SAAS,aAAa,EAAE,EACrC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,GACnD,SAAS,aAAa,EAAE,CAU1B;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,SAAS,aAAa,EAAE,GACpC,aAAa,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAQlE;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,SAAS,aAAa,EAAE,EACrC,OAAO,EAAE,MAAM,GACd,SAAS,aAAa,EAAE,CAS1B"}
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* one puts events in the neighbouring window on exactly the files that bother to state their
|
|
19
19
|
* offset.
|
|
20
20
|
*/
|
|
21
|
+
import { matchesText } from './header/lookup.js';
|
|
21
22
|
import { secondsToTicks } from './tal/ticks.js';
|
|
22
23
|
/**
|
|
23
24
|
* The annotations that overlap a time window, in the recording's own timebase.
|
|
@@ -60,7 +61,9 @@ export function filterAnnotationsByText(annotations, match) {
|
|
|
60
61
|
const test = typeof match === 'string'
|
|
61
62
|
? (text) => text === match
|
|
62
63
|
: match instanceof RegExp
|
|
63
|
-
?
|
|
64
|
+
? // Not `match.test` directly: a `g` or `y` flag makes `test` stateful across the array
|
|
65
|
+
// and silently returns about half the true matches. See `matchesText`.
|
|
66
|
+
matchesText(match)
|
|
64
67
|
: match;
|
|
65
68
|
return Object.freeze(annotations.filter((annotation) => test(annotation.text)));
|
|
66
69
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"annotations-query.js","sourceRoot":"","sources":["../src/annotations-query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGhD;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CACrC,WAAqC,EACrC,MAA2B;IAE3B,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACjD,MAAM,EAAE,GAAG,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IACzD,IAAI,EAAE,IAAI,IAAI;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAEzC,OAAO,MAAM,CAAC,MAAM,CAClB,WAAW,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE;QAChC,MAAM,KAAK,GAAG,UAAU,CAAC,yBAAyB,CAAC;QACnD,MAAM,GAAG,GAAG,KAAK,GAAG,CAAC,UAAU,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC;QACrD,0FAA0F;QAC1F,yFAAyF;QACzF,EAAE;QACF,4EAA4E;QAC5E,2FAA2F;QAC3F,4FAA4F;QAC5F,4FAA4F;QAC5F,0FAA0F;QAC1F,2FAA2F;QAC3F,yCAAyC;QACzC,OAAO,KAAK,GAAG,EAAE,IAAI,CAAC,GAAG,GAAG,IAAI,IAAI,CAAC,GAAG,KAAK,KAAK,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC;IACxE,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CACrC,WAAqC,EACrC,KAAoD;IAEpD,MAAM,IAAI,GACR,OAAO,KAAK,KAAK,QAAQ;QACvB,CAAC,CAAC,CAAC,IAAY,EAAW,EAAE,CAAC,IAAI,KAAK,KAAK;QAC3C,CAAC,CAAC,KAAK,YAAY,MAAM;YACvB,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"annotations-query.js","sourceRoot":"","sources":["../src/annotations-query.ts"],"names":[],"mappings":"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"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -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.2.
|
|
112
|
+
export declare const VERSION = "0.2.21";
|
|
113
113
|
//# sourceMappingURL=constants.d.ts.map
|
package/dist/constants.js
CHANGED
package/dist/header/lookup.d.ts
CHANGED
|
@@ -30,6 +30,22 @@ export declare function findSignals(header: EdfHeader, label: string): readonly
|
|
|
30
30
|
* edfcore could return that would not be a guess.
|
|
31
31
|
*/
|
|
32
32
|
export declare function getSignal(header: EdfHeader, selector: number | string): EdfSignal;
|
|
33
|
+
/**
|
|
34
|
+
* A membership test over a caller's RegExp that cannot be poisoned by its own flags.
|
|
35
|
+
*
|
|
36
|
+
* `RegExp.prototype.test` is STATEFUL when the pattern carries `g` or `y`: it starts from
|
|
37
|
+
* `lastIndex` and advances it on every match. Used across an array — which is what every filter
|
|
38
|
+
* here does — that makes the result depend on what the previous element matched, so `/EEG/g` over
|
|
39
|
+
* four EEG channels returns the first and third and silently drops the other two. The caller sees
|
|
40
|
+
* half a montage with no error, and even a match-everything pattern stops returning every signal
|
|
41
|
+
* once it carries the flag.
|
|
42
|
+
*
|
|
43
|
+
* A `g` flag on a membership test means nothing, so honouring its statefulness serves no one. The
|
|
44
|
+
* regex is CLONED rather than reset in place: resetting the caller's object would mutate an
|
|
45
|
+
* argument, and a module-level `const PATTERN = /x/g` shared with a `String.replace` elsewhere
|
|
46
|
+
* would then behave differently depending on whether edfcore had been called first.
|
|
47
|
+
*/
|
|
48
|
+
export declare function matchesText(match: RegExp): (text: string) => boolean;
|
|
33
49
|
/**
|
|
34
50
|
* Every data signal whose label matches a pattern.
|
|
35
51
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lookup.d.ts","sourceRoot":"","sources":["../../src/header/lookup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGxD;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE,CAGlF;AAMD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAgCjF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,GAC3C,SAAS,SAAS,EAAE,CAKtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAEjE"}
|
|
1
|
+
{"version":3,"file":"lookup.d.ts","sourceRoot":"","sources":["../../src/header/lookup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGxD;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE,CAGlF;AAMD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAgCjF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAQpE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,GAC3C,SAAS,SAAS,EAAE,CAKtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAEjE"}
|
package/dist/header/lookup.js
CHANGED
|
@@ -64,6 +64,30 @@ export function getSignal(header, selector) {
|
|
|
64
64
|
'first is how the wrong channel ends up in a paper. Next: call findSignals() to get them ' +
|
|
65
65
|
'all, or select by index.', { label: trimEdfField(selector), matchingIndices });
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* A membership test over a caller's RegExp that cannot be poisoned by its own flags.
|
|
69
|
+
*
|
|
70
|
+
* `RegExp.prototype.test` is STATEFUL when the pattern carries `g` or `y`: it starts from
|
|
71
|
+
* `lastIndex` and advances it on every match. Used across an array — which is what every filter
|
|
72
|
+
* here does — that makes the result depend on what the previous element matched, so `/EEG/g` over
|
|
73
|
+
* four EEG channels returns the first and third and silently drops the other two. The caller sees
|
|
74
|
+
* half a montage with no error, and even a match-everything pattern stops returning every signal
|
|
75
|
+
* once it carries the flag.
|
|
76
|
+
*
|
|
77
|
+
* A `g` flag on a membership test means nothing, so honouring its statefulness serves no one. The
|
|
78
|
+
* regex is CLONED rather than reset in place: resetting the caller's object would mutate an
|
|
79
|
+
* argument, and a module-level `const PATTERN = /x/g` shared with a `String.replace` elsewhere
|
|
80
|
+
* would then behave differently depending on whether edfcore had been called first.
|
|
81
|
+
*/
|
|
82
|
+
export function matchesText(match) {
|
|
83
|
+
const pattern = new RegExp(match.source, match.flags);
|
|
84
|
+
return (text) => {
|
|
85
|
+
// `y` anchors at `lastIndex`, so this also makes a sticky pattern test from the start of each
|
|
86
|
+
// string rather than from wherever the previous element left off.
|
|
87
|
+
pattern.lastIndex = 0;
|
|
88
|
+
return pattern.test(text);
|
|
89
|
+
};
|
|
90
|
+
}
|
|
67
91
|
/**
|
|
68
92
|
* Every data signal whose label matches a pattern.
|
|
69
93
|
*
|
|
@@ -77,7 +101,7 @@ export function getSignal(header, selector) {
|
|
|
77
101
|
* exact-match case `findSignals` already covers.
|
|
78
102
|
*/
|
|
79
103
|
export function matchSignals(header, match) {
|
|
80
|
-
const test = match instanceof RegExp ? (
|
|
104
|
+
const test = match instanceof RegExp ? matchesText(match) : match;
|
|
81
105
|
return Object.freeze(header.signals.filter((signal) => signal.kind === 'data' && test(signal.label)));
|
|
82
106
|
}
|
|
83
107
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lookup.js","sourceRoot":"","sources":["../../src/header/lookup.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"lookup.js","sourceRoot":"","sources":["../../src/header/lookup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAGjF;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACpC,OAAO,OAAO,KAAK,qBAAqB,IAAI,OAAO,KAAK,qBAAqB,CAAC;AAChF,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,WAAW,CAAC,MAAiB,EAAE,KAAa;IAC1D,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACnC,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC;AACnF,CAAC;AAED,SAAS,WAAW,CAAC,MAAiB;IACpC,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACjF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,MAAiB,EAAE,QAAyB;IACpE,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;QACxC,MAAM,IAAI,uBAAuB,CAC/B,gBAAgB,QAAQ,mBAAmB,MAAM,CAAC,OAAO,CAAC,MAAM,qBAAqB;YACnF,sCAAsC,WAAW,CAAC,MAAM,CAAC,2BAA2B;YACpF,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,eAAe,EAChD,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC5E,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,uBAAuB,CAC/B,yBAAyB,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,yBAAyB;YACtF,oBAAoB,WAAW,CAAC,MAAM,CAAC,+CAA+C;YACtF,wEAAwE,EAC1E,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC5E,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAEvC,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9D,MAAM,IAAI,wBAAwB,CAChC,SAAS,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,YAAY,OAAO,CAAC,MAAM,WAAW;QAClF,YAAY,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,oDAAoD;QAC1F,0FAA0F;QAC1F,0BAA0B,EAC5B,EAAE,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC,EAAE,eAAe,EAAE,CACnD,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACtD,OAAO,CAAC,IAAY,EAAW,EAAE;QAC/B,8FAA8F;QAC9F,kEAAkE;QAClE,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;QACtB,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAiB,EACjB,KAA4C;IAE5C,MAAM,IAAI,GAAG,KAAK,YAAY,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAClE,OAAO,MAAM,CAAC,MAAM,CAClB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAChF,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAiB;IACvD,OAAO,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,qBAAqB,CAAC;AAC3D,CAAC"}
|
package/package.json
CHANGED
package/src/annotations-query.ts
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* offset.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
import { matchesText } from './header/lookup.js';
|
|
22
23
|
import { secondsToTicks } from './tal/ticks.js';
|
|
23
24
|
import type { EdfAnnotation, EdfAnnotationWindow } from './types.js';
|
|
24
25
|
|
|
@@ -73,7 +74,9 @@ export function filterAnnotationsByText(
|
|
|
73
74
|
typeof match === 'string'
|
|
74
75
|
? (text: string): boolean => text === match
|
|
75
76
|
: match instanceof RegExp
|
|
76
|
-
?
|
|
77
|
+
? // Not `match.test` directly: a `g` or `y` flag makes `test` stateful across the array
|
|
78
|
+
// and silently returns about half the true matches. See `matchesText`.
|
|
79
|
+
matchesText(match)
|
|
77
80
|
: match;
|
|
78
81
|
return Object.freeze(annotations.filter((annotation) => test(annotation.text)));
|
|
79
82
|
}
|
package/src/constants.ts
CHANGED
package/src/header/lookup.ts
CHANGED
|
@@ -80,6 +80,31 @@ export function getSignal(header: EdfHeader, selector: number | string): EdfSign
|
|
|
80
80
|
);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* A membership test over a caller's RegExp that cannot be poisoned by its own flags.
|
|
85
|
+
*
|
|
86
|
+
* `RegExp.prototype.test` is STATEFUL when the pattern carries `g` or `y`: it starts from
|
|
87
|
+
* `lastIndex` and advances it on every match. Used across an array — which is what every filter
|
|
88
|
+
* here does — that makes the result depend on what the previous element matched, so `/EEG/g` over
|
|
89
|
+
* four EEG channels returns the first and third and silently drops the other two. The caller sees
|
|
90
|
+
* half a montage with no error, and even a match-everything pattern stops returning every signal
|
|
91
|
+
* once it carries the flag.
|
|
92
|
+
*
|
|
93
|
+
* A `g` flag on a membership test means nothing, so honouring its statefulness serves no one. The
|
|
94
|
+
* regex is CLONED rather than reset in place: resetting the caller's object would mutate an
|
|
95
|
+
* argument, and a module-level `const PATTERN = /x/g` shared with a `String.replace` elsewhere
|
|
96
|
+
* would then behave differently depending on whether edfcore had been called first.
|
|
97
|
+
*/
|
|
98
|
+
export function matchesText(match: RegExp): (text: string) => boolean {
|
|
99
|
+
const pattern = new RegExp(match.source, match.flags);
|
|
100
|
+
return (text: string): boolean => {
|
|
101
|
+
// `y` anchors at `lastIndex`, so this also makes a sticky pattern test from the start of each
|
|
102
|
+
// string rather than from wherever the previous element left off.
|
|
103
|
+
pattern.lastIndex = 0;
|
|
104
|
+
return pattern.test(text);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
83
108
|
/**
|
|
84
109
|
* Every data signal whose label matches a pattern.
|
|
85
110
|
*
|
|
@@ -96,7 +121,7 @@ export function matchSignals(
|
|
|
96
121
|
header: EdfHeader,
|
|
97
122
|
match: RegExp | ((label: string) => boolean),
|
|
98
123
|
): readonly EdfSignal[] {
|
|
99
|
-
const test = match instanceof RegExp ? (
|
|
124
|
+
const test = match instanceof RegExp ? matchesText(match) : match;
|
|
100
125
|
return Object.freeze(
|
|
101
126
|
header.signals.filter((signal) => signal.kind === 'data' && test(signal.label)),
|
|
102
127
|
);
|