/** * Checking the options a caller passed, before anything is written. * * The command line has always validated these — `--decimals 1.5` is a usage error and always * has been — and the library did not, so the same value behaved differently depending on how * it arrived. `convert(file, { decimals: NaN })` resolved successfully having written whole * numbers into a column the caller had asked for decimals in, which is the worst of the * three: no error, no warning, and output that looks like a deliberate choice. `decimals: -1` * reached `toFixed` and came back as a bare RangeError from deep inside the formatter, naming * nothing the caller had written. `start: NaN` created the output directory, wrote * signals.csv, and then failed with a message about the input being unreadable — a partial * conversion, blamed on the file. * * These run at the top of `buildPlan`, which every path goes through before a directory is * created or a stream is opened, so a rejected option leaves nothing behind. */ /** A problem with the options a caller passed, as opposed to a problem with the file. */ export declare class OptionError extends Error { constructor(message: string); } /** * The largest `--decimals` accepts, and what both documentation pages state. * * Not a limit of `toFixed`, whatever this comment used to say. `toFixed` takes 0 to 100 and * throws a RangeError at 101 — which is exactly the belief `MAX_DERIVED_DECIMALS` in * edf/scale.ts exists to correct, having once clamped the *derived* precision to 20 on the * same wrong grounds and rounded a magnetometer channel needing 23 places onto a grid three * digital codes wide, losing 69% of its samples in silence. * * Twenty is a bound on a number a person types by hand, not on what the format can express. * The derived precision, which nobody types, runs to 100 and says so. */ export declare const MAX_DECIMALS = 20; export declare function assertOptions(options: { decimals?: number | undefined; start?: number | undefined; duration?: number | undefined; end?: number | undefined; layout?: string | undefined; channels?: readonly string[] | undefined; outputDir?: string | undefined; annotationsOnly?: boolean | undefined; gzip?: boolean | undefined; bom?: boolean | undefined; force?: boolean | undefined; checksum?: boolean | undefined; toStdout?: boolean | undefined; onProgress?: unknown; startText?: unknown; durationText?: unknown; endText?: unknown; }): void; /** * The channel list two exported functions take, checked the way their other argument is. * * `selectChannels(signals, terms)` has checked `terms` since 0.6.x — "`'ECG'` was iterated * character by character and answered `No channel named \"E\"`… naming nothing the caller had * written" — and never checked `signals`, which is the argument in front of it. Passing one * signal where the list goes, or a header where its `signals` goes, came back as * `TypeError: signals.filter is not a function`: a local of this package, over a value the * caller did write. * * `buildColumnNames` is worse off, because a string is iterable. `buildColumnNames('ECG')` * returned `Map { null => 'undefined_chundefined' }` and no error at all — a column name for a * channel that does not exist, keyed by a position that is not one. * * The bad entry is named by position rather than the whole list being printed back: a header * may declare hundreds of channels, and a message is not the place for all of them. */ export declare function assertSignals(signals: unknown): void; /** * What `buildPlan` is told about the recording, checked the way what it is asked for is. * * `assertOptions` runs at the top of `buildPlan` and covers the second argument completely. * The first was not looked at, and it is the one carrying the numbers every figure in the plan * is derived from. Two of them missing produced a plan rather than an error: * * buildPlan({ signals, recordDuration: 1 }, {}) * // groups: 3, estimate.rows: 0, range.endSeconds: null * * A plan saying the conversion writes nothing, handed back as an answer — which is the "takes * the whole recording without saying so" this checker exists to stop, one field over. A record * count below zero was worse: it came back as * * TimeRangeError: --start 0s is at or past the end of this -5s recording. * * a flag the caller never passed, about a recording that cannot exist, blaming the request for * the input. And `recordDuration: '1'` was coerced by the arithmetic and accepted, where the * same string is refused for `end` two functions down. * * A real header cannot produce any of them: the parser refuses a record duration that is not a * positive number, "Infinity" included. */ export declare function assertPlanInput(input: { signals?: unknown; recordDuration?: unknown; recordCount?: unknown; }): void; /** * The two numbers a window is measured against, apart from the channel list. * * `resolveRange` is exported on its own and has its own signature block on the api page, and * `buildPlan` calls it — so it was covered only from above. Called directly it took both * numbers unexamined and answered with a range: * * resolveRange({ recordDuration: 1 }) // recordCount undefined * // { startSeconds: 0, endSeconds: null, startRecord: 0, endRecord: 0 } * * A range over no records, returned as a fact about a recording. Its own opening comment * already says why that is the wrong answer — "no error, no warning, and a range read back as * `startSeconds: null, startRecord: null`, which is the 'takes the whole recording without * saying so'" — about the three fields it does check. `resolveRange(42)` went the same way, * since reading `.start` off a number is `undefined` rather than a throw. * * Split out rather than calling `assertPlanInput`, which would demand a channel list this * function never looks at. */ export declare function assertRecordShape(input: { recordDuration?: unknown; recordCount?: unknown; recordStarts?: unknown; }): void; /** * The recording to read, checked before it is opened. * * `EdfFile.open` hands whatever it is given to `fs`, and the refusal comes back as an * `EdfError` coded `UNREADABLE`, hinted "Check the path is spelled the way it is on disk and * that you have permission to read it" — advice about a path, over a value that is not one, * filed as a problem with the recording rather than with the call. `convert({ input: 'a.edf' })`, * which is the option-bag shape the second parameter has, answered `Cannot read "[object * Object]"`; `convert(['a.edf', 'b.edf'])` answered `Cannot read "a.edf,b.edf"`, a path the * caller never wrote, because `String` of an array joins it with commas. * * The empty string is left to `fs`, which has no such file and says so truthfully — the same * reasoning `outputDir` states for not trimming: a path is not a keyword. */ export declare function assertInputPath(input: unknown): void; /** * How a rejected value reads in the refusal: numbers bare, everything else quoted so its * type is visible. * * `JSON.stringify` has no text for a function or a symbol — it returns `undefined`, not a * string — so `layout: () => 'long'` came back as `layout must be "wide" or "long", got * undefined.`, which names the one value that does not raise this: every option here is * optional, and `undefined` is how a caller says they are not passing it. `input` was worse, * since `convert(undefined)` and `convert(someFunction)` then produced the same sentence, and * the first is a forgotten argument while the second is a wrong one. * * Exported because time-range.ts had the identical function, fixed there and not here — the * same two-copies-of-one-helper the derived precision and the pluraliser were each pulled * together for. */ export declare function describeValue(value: unknown): string;