@cosyte/astm 0.0.9 → 0.0.10

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/dist/index.d.cts CHANGED
@@ -4360,12 +4360,49 @@ declare function decodeAstmFrames(bytes: Uint8Array, options?: FrameOptions): De
4360
4360
  *
4361
4361
  * A record must carry bytes: an empty record (or an empty record list) is a typed
4362
4362
  * {@link AstmFrameEncodeError}, never an empty frame.
4363
+ *
4364
+ * **A record given as a `string` is a byte string.** Each character stands for one
4365
+ * byte, so a character above `U+00FF` has no byte to stand for and the record is
4366
+ * refused rather than written. See {@link AstmFrameEncodeError} for what that
4367
+ * turns away and how to frame such content instead.
4368
+ */
4369
+ /**
4370
+ * The reasons {@link composeAstmFrames} refuses rather than emitting bytes that
4371
+ * are not the record it was handed.
4372
+ *
4373
+ * - `ASTM_FRAME_EMPTY_RECORD`: an empty record list, or a record with no bytes.
4374
+ * A frame must carry a record; an empty one is a structural error, never an
4375
+ * empty frame.
4376
+ * - `ASTM_FRAME_UNENCODABLE_CHARACTER`: a record given as a `string` holds a
4377
+ * character above `U+00FF`, which has no single byte to stand for.
4378
+ *
4379
+ * @example
4380
+ * ```ts
4381
+ * import type { AstmFrameEncodeErrorCode } from "@cosyte/astm";
4382
+ * const code: AstmFrameEncodeErrorCode = "ASTM_FRAME_UNENCODABLE_CHARACTER";
4383
+ * ```
4363
4384
  */
4385
+ type AstmFrameEncodeErrorCode = "ASTM_FRAME_EMPTY_RECORD" | "ASTM_FRAME_UNENCODABLE_CHARACTER";
4364
4386
  /**
4365
4387
  * Thrown by {@link composeAstmFrames} when the input cannot be framed into a
4366
- * spec-clean stream: an empty record list, or a record with no bytes (a frame
4367
- * must carry a record; an empty one is a structural error, never an empty frame).
4368
- * Carries a stable code + the offending record index, never record bytes.
4388
+ * spec-clean stream. Carries a stable code + positional context, never the
4389
+ * record bytes and never the offending character (PHI discipline).
4390
+ *
4391
+ * **The unencodable-character case, and why it is a refusal.** A record passed as
4392
+ * a `string` is a **byte string**: character `i` becomes byte `i`, which is the
4393
+ * exact inverse of how this package turns record bytes back into a string (one
4394
+ * `String.fromCharCode` per byte, so every byte survives 1:1). A character above
4395
+ * `U+00FF` has no byte to become. Turning one into bytes takes a character
4396
+ * encoding, and nothing this package reads from an ASTM stream says which one:
4397
+ * it reads no character-set declaration from any record, so picking one would be
4398
+ * a guess at bytes the caller never supplied. Emit also has no warning channel,
4399
+ * so a warning here could only be ignored while the wrong bytes still shipped.
4400
+ *
4401
+ * **Framing content outside Latin-1.** Encode it yourself, with the code page
4402
+ * your instrument actually uses, and hand {@link composeAstmFrames} the
4403
+ * `Uint8Array`: it accepts bytes directly and writes them through untouched.
4404
+ * The refusal removes no capability, it routes you to the parameter that already
4405
+ * carried it.
4369
4406
  *
4370
4407
  * @example
4371
4408
  * ```ts
@@ -4379,11 +4416,17 @@ declare function decodeAstmFrames(bytes: Uint8Array, options?: FrameOptions): De
4379
4416
  */
4380
4417
  declare class AstmFrameEncodeError extends Error {
4381
4418
  /** Stable discriminant. */
4382
- readonly code: "ASTM_FRAME_EMPTY_RECORD";
4419
+ readonly code: AstmFrameEncodeErrorCode;
4383
4420
  /** Index of the offending record within the input, when applicable. */
4384
4421
  readonly recordIndex?: number;
4422
+ /**
4423
+ * Position of the offending character within that record, when applicable:
4424
+ * its index in the string, never the character itself and never its code
4425
+ * point. Enough to find it in the caller's own data.
4426
+ */
4427
+ readonly characterIndex?: number;
4385
4428
  /** @internal */
4386
- constructor(message: string, recordIndex?: number);
4429
+ constructor(message: string, recordIndex?: number, code?: AstmFrameEncodeErrorCode, characterIndex?: number);
4387
4430
  }
4388
4431
  /** Options for {@link composeAstmFrames}. */
4389
4432
  interface ComposeFramesOptions {
@@ -4402,11 +4445,31 @@ interface ComposeFramesOptions {
4402
4445
  * across the whole stream; every frame's modulo-256 checksum is computed and
4403
4446
  * emitted uppercase.
4404
4447
  *
4448
+ * **A record in either accepted form is written through unchanged, or refused.** A
4449
+ * record given as a `Uint8Array` is already bytes. A record given as a `string` is
4450
+ * a **byte string**, character `i` becoming byte `i`, the exact inverse of how a
4451
+ * decoded record becomes a string again. A character above `U+00FF` is not a byte,
4452
+ * so it is refused with `ASTM_FRAME_UNENCODABLE_CHARACTER` rather than replaced by
4453
+ * a different character (it used to be truncated to its low byte, which is another
4454
+ * ordinary character, and reached the wire silently). To frame content outside
4455
+ * Latin-1, encode it with the character encoding your instrument uses and pass the
4456
+ * resulting `Uint8Array`. Those two forms are the whole of what `records` accepts.
4457
+ * A caller reaching this from JavaScript with some **other** typed array is outside
4458
+ * the signature and gets no such refusal: each element is still written as its low
4459
+ * byte, the same substitution described above. Pass a `Uint8Array` or a string.
4460
+ *
4461
+ * That covers the string-to-bytes step only. It is **not** a guarantee that any
4462
+ * accepted record reads back: a record already carrying an `STX`, `ETX` or `ETB`
4463
+ * byte is framed as given and re-decodes wrong, which this refusal does not touch
4464
+ * and does not claim to.
4465
+ *
4405
4466
  * @param records - The reassembled record byte-strings (`Uint8Array` or latin1
4406
4467
  * `string`), one entry per complete record.
4407
4468
  * @param options - Encode options.
4408
4469
  * @returns The framed byte stream.
4409
- * @throws {@link AstmFrameEncodeError} when the list is empty or a record has no bytes.
4470
+ * @throws {@link AstmFrameEncodeError} when the list is empty, a record has no
4471
+ * bytes (`ASTM_FRAME_EMPTY_RECORD`), or a record string holds a character above
4472
+ * `U+00FF` (`ASTM_FRAME_UNENCODABLE_CHARACTER`).
4410
4473
  * @example
4411
4474
  * ```ts
4412
4475
  * import { composeAstmFrames, decodeAstmFrames } from "@cosyte/astm";
@@ -4483,11 +4546,18 @@ declare function parseFramedAstm(bytes: Uint8Array, options?: FrameOptions & Ast
4483
4546
  * {@link decodeAstmFrames} reassembles: `parseFramedAstm(serializeFramedAstm(msg))`
4484
4547
  * yields an equal message.
4485
4548
  *
4549
+ * A value carrying a character above `U+00FF` is **refused** here rather than
4550
+ * framed: the record layer is happy to hold one, but a frame carries bytes and
4551
+ * nothing in the message says which character encoding to turn it into. A message
4552
+ * whose every value is Latin-1 is unaffected.
4553
+ *
4486
4554
  * @param input - A parsed {@link AstmMessage} or a list of {@link AstmRecord}s.
4487
4555
  * @param options - Frame-encode options.
4488
4556
  * @returns The framed byte stream.
4489
4557
  * @throws {@link AstmSerializeError} when a value contains an unencodable `CR`/`LF`.
4490
- * @throws {@link AstmFrameEncodeError} when there are no records to frame.
4558
+ * @throws {@link AstmFrameEncodeError} when there are no records to frame
4559
+ * (`ASTM_FRAME_EMPTY_RECORD`), or a value holds a character above `U+00FF`
4560
+ * (`ASTM_FRAME_UNENCODABLE_CHARACTER`).
4491
4561
  * @example
4492
4562
  * ```ts
4493
4563
  * import { parseAstmRecords, serializeFramedAstm, parseFramedAstm } from "@cosyte/astm";
@@ -4659,4 +4729,4 @@ declare class AstmFrameStrictError extends Error {
4659
4729
  */
4660
4730
  declare const VERSION: string;
4661
4731
 
4662
- export { ALL_ASTM_WARNING_CODES, AMBIGUOUS_CODES, ACK as ASTM_ACK, ENQ as ASTM_ENQ, EOT as ASTM_EOT, NAK as ASTM_NAK, type AbnormalFlag, type AbnormalFlagCode, type AbnormalFlagMeaning, type AmbiguousCode, type AnyAstmWarningCode, AstmAmbiguousStreamError, type AstmDate, type AstmDatePrecision, type AstmField, type AstmFrame, AstmFrameEncodeError, type AstmFramePosition, AstmFrameStrictError, type AstmFrameWarning, type AstmFraming, type AstmLivdWarning, type AstmLtpWarning, type AstmMessage, type AstmMessageClassification, type AstmMessageKind, AstmParseError, type AstmParseOptions, type AstmPosition, type AstmProfile, AstmProfileDefinitionError, type AstmProfileProvenance, type AstmQuirkMatch, type AstmQuirkTolerance, type AstmRecord, type AstmRecordInput, type AstmRecordWarning, AstmSerializeError, type AstmSerializeErrorCode, type AstmStreamMessage, AstmStrictError, CANONICAL_DELIMITERS, type CommentInput, type CommentRecord, type ComposeFramesOptions, type DecodeAstmFramesResult, type DefineAstmProfileOptions, type Delimiters, type DetectFramingOptions, type DetectFramingResult, FATAL_CODES, FRAME_WARNING_CODES, type FatalCode, type FrameChecksum, type FrameOptions, type FrameTerminator, type FrameWarningCode, type FramedAstmResult, type HeaderInput, type HeaderRecord, LIVD_WARNING_CODES, LTP_WARNING_CODES, type LivdAnnotation, type LivdCatalog, type LivdEntry, type LivdLookup, type LivdMapping, type LivdResult, type LivdWarningCode, type LtpAction, type LtpEvent, type LtpPhase, type LtpState, type LtpTransition, type LtpWarningCode, type ManufacturerRecord, type MessageInput, type OrderInput, type OrderRecord, type PatientInput, type PatientName, type PatientNameInput, type PatientRecord, type QueryInput, type QueryRecord, type ReferenceRange, type ReferenceRangeKind, type ResultInput, type ResultRecord, type ResultStatus, type ResultStatusCode, type ResultStatusMeaning, SAFETY_CRITICAL_CODES, type ScientificRecord, TOLERABLE_CODES, type TerminatorRecord, type UniversalTestId, type UniversalTestIdProvenance, type UnknownEscapeSink, type UnpairedEscapeSink, type UnsupportedRecord, VERSION, type VerbatimInput, WARNING_CODES, type WarningCode, ambiguousMessageKind, ambiguousValueSplit, applyAstmProfile, applyAstmProfileToWarnings, applyLivd, astmDateToLocalISO, astmProfiles, attachComments, buildAstmMessage, classifyMessage, comments, commentsFor, composeAstmFrames, computeChecksum, decodeAstmFrames, decodeEscapes, deepFreeze, defineAstmProfile, defineLivdCatalog, delimitersRedeclared, detectFraming, encodeComponent, fieldScalar, fieldsUnseparated, frameBadChecksum, frameOversize, frameSequenceGap, frameUnterminated, getAstmProfile, getDefaultAstmProfile, interpretAbnormalFlag, interpretResultStatus, isNonStandard, isSafetyCriticalCode, listAstmProfiles, livdAmbiguousMapping, livdUnmappedCode, lookupLivdForRecord, ltpAmbiguousTransport, ltpFrameRejected, ltpInitialState, ltpReduce, ltpUnexpectedEvent, messages, nonStandardDelimiters, orders, orphanComment, parseAstmDate, parseAstmRecords, parseChecksumHex, parseFramedAstm, parseReferenceRange, partialTimestamp, patient, primaryCode, profileQuirkApplied, query, readDelimiters, recognizeUniversalTestId, resolveProfileTransport, results, serializeAstmRecord, serializeAstmRecords, serializeField, serializeFramedAstm, setDefaultAstmProfile, splitEscapeAware, toChecksumHex, tokenizeHeader, tokenizeRecord, undefinedAbnormalFlag, undefinedResultStatus, uninterpretedQueryStatus, unitsAbsent, unknownEscapeSequence, unknownRecordType, unpairedEscapeCharacter, unparseableReferenceRange, unreadableRedeclaration };
4732
+ export { ALL_ASTM_WARNING_CODES, AMBIGUOUS_CODES, ACK as ASTM_ACK, ENQ as ASTM_ENQ, EOT as ASTM_EOT, NAK as ASTM_NAK, type AbnormalFlag, type AbnormalFlagCode, type AbnormalFlagMeaning, type AmbiguousCode, type AnyAstmWarningCode, AstmAmbiguousStreamError, type AstmDate, type AstmDatePrecision, type AstmField, type AstmFrame, AstmFrameEncodeError, type AstmFrameEncodeErrorCode, type AstmFramePosition, AstmFrameStrictError, type AstmFrameWarning, type AstmFraming, type AstmLivdWarning, type AstmLtpWarning, type AstmMessage, type AstmMessageClassification, type AstmMessageKind, AstmParseError, type AstmParseOptions, type AstmPosition, type AstmProfile, AstmProfileDefinitionError, type AstmProfileProvenance, type AstmQuirkMatch, type AstmQuirkTolerance, type AstmRecord, type AstmRecordInput, type AstmRecordWarning, AstmSerializeError, type AstmSerializeErrorCode, type AstmStreamMessage, AstmStrictError, CANONICAL_DELIMITERS, type CommentInput, type CommentRecord, type ComposeFramesOptions, type DecodeAstmFramesResult, type DefineAstmProfileOptions, type Delimiters, type DetectFramingOptions, type DetectFramingResult, FATAL_CODES, FRAME_WARNING_CODES, type FatalCode, type FrameChecksum, type FrameOptions, type FrameTerminator, type FrameWarningCode, type FramedAstmResult, type HeaderInput, type HeaderRecord, LIVD_WARNING_CODES, LTP_WARNING_CODES, type LivdAnnotation, type LivdCatalog, type LivdEntry, type LivdLookup, type LivdMapping, type LivdResult, type LivdWarningCode, type LtpAction, type LtpEvent, type LtpPhase, type LtpState, type LtpTransition, type LtpWarningCode, type ManufacturerRecord, type MessageInput, type OrderInput, type OrderRecord, type PatientInput, type PatientName, type PatientNameInput, type PatientRecord, type QueryInput, type QueryRecord, type ReferenceRange, type ReferenceRangeKind, type ResultInput, type ResultRecord, type ResultStatus, type ResultStatusCode, type ResultStatusMeaning, SAFETY_CRITICAL_CODES, type ScientificRecord, TOLERABLE_CODES, type TerminatorRecord, type UniversalTestId, type UniversalTestIdProvenance, type UnknownEscapeSink, type UnpairedEscapeSink, type UnsupportedRecord, VERSION, type VerbatimInput, WARNING_CODES, type WarningCode, ambiguousMessageKind, ambiguousValueSplit, applyAstmProfile, applyAstmProfileToWarnings, applyLivd, astmDateToLocalISO, astmProfiles, attachComments, buildAstmMessage, classifyMessage, comments, commentsFor, composeAstmFrames, computeChecksum, decodeAstmFrames, decodeEscapes, deepFreeze, defineAstmProfile, defineLivdCatalog, delimitersRedeclared, detectFraming, encodeComponent, fieldScalar, fieldsUnseparated, frameBadChecksum, frameOversize, frameSequenceGap, frameUnterminated, getAstmProfile, getDefaultAstmProfile, interpretAbnormalFlag, interpretResultStatus, isNonStandard, isSafetyCriticalCode, listAstmProfiles, livdAmbiguousMapping, livdUnmappedCode, lookupLivdForRecord, ltpAmbiguousTransport, ltpFrameRejected, ltpInitialState, ltpReduce, ltpUnexpectedEvent, messages, nonStandardDelimiters, orders, orphanComment, parseAstmDate, parseAstmRecords, parseChecksumHex, parseFramedAstm, parseReferenceRange, partialTimestamp, patient, primaryCode, profileQuirkApplied, query, readDelimiters, recognizeUniversalTestId, resolveProfileTransport, results, serializeAstmRecord, serializeAstmRecords, serializeField, serializeFramedAstm, setDefaultAstmProfile, splitEscapeAware, toChecksumHex, tokenizeHeader, tokenizeRecord, undefinedAbnormalFlag, undefinedResultStatus, uninterpretedQueryStatus, unitsAbsent, unknownEscapeSequence, unknownRecordType, unpairedEscapeCharacter, unparseableReferenceRange, unreadableRedeclaration };
package/dist/index.d.ts CHANGED
@@ -4360,12 +4360,49 @@ declare function decodeAstmFrames(bytes: Uint8Array, options?: FrameOptions): De
4360
4360
  *
4361
4361
  * A record must carry bytes: an empty record (or an empty record list) is a typed
4362
4362
  * {@link AstmFrameEncodeError}, never an empty frame.
4363
+ *
4364
+ * **A record given as a `string` is a byte string.** Each character stands for one
4365
+ * byte, so a character above `U+00FF` has no byte to stand for and the record is
4366
+ * refused rather than written. See {@link AstmFrameEncodeError} for what that
4367
+ * turns away and how to frame such content instead.
4368
+ */
4369
+ /**
4370
+ * The reasons {@link composeAstmFrames} refuses rather than emitting bytes that
4371
+ * are not the record it was handed.
4372
+ *
4373
+ * - `ASTM_FRAME_EMPTY_RECORD`: an empty record list, or a record with no bytes.
4374
+ * A frame must carry a record; an empty one is a structural error, never an
4375
+ * empty frame.
4376
+ * - `ASTM_FRAME_UNENCODABLE_CHARACTER`: a record given as a `string` holds a
4377
+ * character above `U+00FF`, which has no single byte to stand for.
4378
+ *
4379
+ * @example
4380
+ * ```ts
4381
+ * import type { AstmFrameEncodeErrorCode } from "@cosyte/astm";
4382
+ * const code: AstmFrameEncodeErrorCode = "ASTM_FRAME_UNENCODABLE_CHARACTER";
4383
+ * ```
4363
4384
  */
4385
+ type AstmFrameEncodeErrorCode = "ASTM_FRAME_EMPTY_RECORD" | "ASTM_FRAME_UNENCODABLE_CHARACTER";
4364
4386
  /**
4365
4387
  * Thrown by {@link composeAstmFrames} when the input cannot be framed into a
4366
- * spec-clean stream: an empty record list, or a record with no bytes (a frame
4367
- * must carry a record; an empty one is a structural error, never an empty frame).
4368
- * Carries a stable code + the offending record index, never record bytes.
4388
+ * spec-clean stream. Carries a stable code + positional context, never the
4389
+ * record bytes and never the offending character (PHI discipline).
4390
+ *
4391
+ * **The unencodable-character case, and why it is a refusal.** A record passed as
4392
+ * a `string` is a **byte string**: character `i` becomes byte `i`, which is the
4393
+ * exact inverse of how this package turns record bytes back into a string (one
4394
+ * `String.fromCharCode` per byte, so every byte survives 1:1). A character above
4395
+ * `U+00FF` has no byte to become. Turning one into bytes takes a character
4396
+ * encoding, and nothing this package reads from an ASTM stream says which one:
4397
+ * it reads no character-set declaration from any record, so picking one would be
4398
+ * a guess at bytes the caller never supplied. Emit also has no warning channel,
4399
+ * so a warning here could only be ignored while the wrong bytes still shipped.
4400
+ *
4401
+ * **Framing content outside Latin-1.** Encode it yourself, with the code page
4402
+ * your instrument actually uses, and hand {@link composeAstmFrames} the
4403
+ * `Uint8Array`: it accepts bytes directly and writes them through untouched.
4404
+ * The refusal removes no capability, it routes you to the parameter that already
4405
+ * carried it.
4369
4406
  *
4370
4407
  * @example
4371
4408
  * ```ts
@@ -4379,11 +4416,17 @@ declare function decodeAstmFrames(bytes: Uint8Array, options?: FrameOptions): De
4379
4416
  */
4380
4417
  declare class AstmFrameEncodeError extends Error {
4381
4418
  /** Stable discriminant. */
4382
- readonly code: "ASTM_FRAME_EMPTY_RECORD";
4419
+ readonly code: AstmFrameEncodeErrorCode;
4383
4420
  /** Index of the offending record within the input, when applicable. */
4384
4421
  readonly recordIndex?: number;
4422
+ /**
4423
+ * Position of the offending character within that record, when applicable:
4424
+ * its index in the string, never the character itself and never its code
4425
+ * point. Enough to find it in the caller's own data.
4426
+ */
4427
+ readonly characterIndex?: number;
4385
4428
  /** @internal */
4386
- constructor(message: string, recordIndex?: number);
4429
+ constructor(message: string, recordIndex?: number, code?: AstmFrameEncodeErrorCode, characterIndex?: number);
4387
4430
  }
4388
4431
  /** Options for {@link composeAstmFrames}. */
4389
4432
  interface ComposeFramesOptions {
@@ -4402,11 +4445,31 @@ interface ComposeFramesOptions {
4402
4445
  * across the whole stream; every frame's modulo-256 checksum is computed and
4403
4446
  * emitted uppercase.
4404
4447
  *
4448
+ * **A record in either accepted form is written through unchanged, or refused.** A
4449
+ * record given as a `Uint8Array` is already bytes. A record given as a `string` is
4450
+ * a **byte string**, character `i` becoming byte `i`, the exact inverse of how a
4451
+ * decoded record becomes a string again. A character above `U+00FF` is not a byte,
4452
+ * so it is refused with `ASTM_FRAME_UNENCODABLE_CHARACTER` rather than replaced by
4453
+ * a different character (it used to be truncated to its low byte, which is another
4454
+ * ordinary character, and reached the wire silently). To frame content outside
4455
+ * Latin-1, encode it with the character encoding your instrument uses and pass the
4456
+ * resulting `Uint8Array`. Those two forms are the whole of what `records` accepts.
4457
+ * A caller reaching this from JavaScript with some **other** typed array is outside
4458
+ * the signature and gets no such refusal: each element is still written as its low
4459
+ * byte, the same substitution described above. Pass a `Uint8Array` or a string.
4460
+ *
4461
+ * That covers the string-to-bytes step only. It is **not** a guarantee that any
4462
+ * accepted record reads back: a record already carrying an `STX`, `ETX` or `ETB`
4463
+ * byte is framed as given and re-decodes wrong, which this refusal does not touch
4464
+ * and does not claim to.
4465
+ *
4405
4466
  * @param records - The reassembled record byte-strings (`Uint8Array` or latin1
4406
4467
  * `string`), one entry per complete record.
4407
4468
  * @param options - Encode options.
4408
4469
  * @returns The framed byte stream.
4409
- * @throws {@link AstmFrameEncodeError} when the list is empty or a record has no bytes.
4470
+ * @throws {@link AstmFrameEncodeError} when the list is empty, a record has no
4471
+ * bytes (`ASTM_FRAME_EMPTY_RECORD`), or a record string holds a character above
4472
+ * `U+00FF` (`ASTM_FRAME_UNENCODABLE_CHARACTER`).
4410
4473
  * @example
4411
4474
  * ```ts
4412
4475
  * import { composeAstmFrames, decodeAstmFrames } from "@cosyte/astm";
@@ -4483,11 +4546,18 @@ declare function parseFramedAstm(bytes: Uint8Array, options?: FrameOptions & Ast
4483
4546
  * {@link decodeAstmFrames} reassembles: `parseFramedAstm(serializeFramedAstm(msg))`
4484
4547
  * yields an equal message.
4485
4548
  *
4549
+ * A value carrying a character above `U+00FF` is **refused** here rather than
4550
+ * framed: the record layer is happy to hold one, but a frame carries bytes and
4551
+ * nothing in the message says which character encoding to turn it into. A message
4552
+ * whose every value is Latin-1 is unaffected.
4553
+ *
4486
4554
  * @param input - A parsed {@link AstmMessage} or a list of {@link AstmRecord}s.
4487
4555
  * @param options - Frame-encode options.
4488
4556
  * @returns The framed byte stream.
4489
4557
  * @throws {@link AstmSerializeError} when a value contains an unencodable `CR`/`LF`.
4490
- * @throws {@link AstmFrameEncodeError} when there are no records to frame.
4558
+ * @throws {@link AstmFrameEncodeError} when there are no records to frame
4559
+ * (`ASTM_FRAME_EMPTY_RECORD`), or a value holds a character above `U+00FF`
4560
+ * (`ASTM_FRAME_UNENCODABLE_CHARACTER`).
4491
4561
  * @example
4492
4562
  * ```ts
4493
4563
  * import { parseAstmRecords, serializeFramedAstm, parseFramedAstm } from "@cosyte/astm";
@@ -4659,4 +4729,4 @@ declare class AstmFrameStrictError extends Error {
4659
4729
  */
4660
4730
  declare const VERSION: string;
4661
4731
 
4662
- export { ALL_ASTM_WARNING_CODES, AMBIGUOUS_CODES, ACK as ASTM_ACK, ENQ as ASTM_ENQ, EOT as ASTM_EOT, NAK as ASTM_NAK, type AbnormalFlag, type AbnormalFlagCode, type AbnormalFlagMeaning, type AmbiguousCode, type AnyAstmWarningCode, AstmAmbiguousStreamError, type AstmDate, type AstmDatePrecision, type AstmField, type AstmFrame, AstmFrameEncodeError, type AstmFramePosition, AstmFrameStrictError, type AstmFrameWarning, type AstmFraming, type AstmLivdWarning, type AstmLtpWarning, type AstmMessage, type AstmMessageClassification, type AstmMessageKind, AstmParseError, type AstmParseOptions, type AstmPosition, type AstmProfile, AstmProfileDefinitionError, type AstmProfileProvenance, type AstmQuirkMatch, type AstmQuirkTolerance, type AstmRecord, type AstmRecordInput, type AstmRecordWarning, AstmSerializeError, type AstmSerializeErrorCode, type AstmStreamMessage, AstmStrictError, CANONICAL_DELIMITERS, type CommentInput, type CommentRecord, type ComposeFramesOptions, type DecodeAstmFramesResult, type DefineAstmProfileOptions, type Delimiters, type DetectFramingOptions, type DetectFramingResult, FATAL_CODES, FRAME_WARNING_CODES, type FatalCode, type FrameChecksum, type FrameOptions, type FrameTerminator, type FrameWarningCode, type FramedAstmResult, type HeaderInput, type HeaderRecord, LIVD_WARNING_CODES, LTP_WARNING_CODES, type LivdAnnotation, type LivdCatalog, type LivdEntry, type LivdLookup, type LivdMapping, type LivdResult, type LivdWarningCode, type LtpAction, type LtpEvent, type LtpPhase, type LtpState, type LtpTransition, type LtpWarningCode, type ManufacturerRecord, type MessageInput, type OrderInput, type OrderRecord, type PatientInput, type PatientName, type PatientNameInput, type PatientRecord, type QueryInput, type QueryRecord, type ReferenceRange, type ReferenceRangeKind, type ResultInput, type ResultRecord, type ResultStatus, type ResultStatusCode, type ResultStatusMeaning, SAFETY_CRITICAL_CODES, type ScientificRecord, TOLERABLE_CODES, type TerminatorRecord, type UniversalTestId, type UniversalTestIdProvenance, type UnknownEscapeSink, type UnpairedEscapeSink, type UnsupportedRecord, VERSION, type VerbatimInput, WARNING_CODES, type WarningCode, ambiguousMessageKind, ambiguousValueSplit, applyAstmProfile, applyAstmProfileToWarnings, applyLivd, astmDateToLocalISO, astmProfiles, attachComments, buildAstmMessage, classifyMessage, comments, commentsFor, composeAstmFrames, computeChecksum, decodeAstmFrames, decodeEscapes, deepFreeze, defineAstmProfile, defineLivdCatalog, delimitersRedeclared, detectFraming, encodeComponent, fieldScalar, fieldsUnseparated, frameBadChecksum, frameOversize, frameSequenceGap, frameUnterminated, getAstmProfile, getDefaultAstmProfile, interpretAbnormalFlag, interpretResultStatus, isNonStandard, isSafetyCriticalCode, listAstmProfiles, livdAmbiguousMapping, livdUnmappedCode, lookupLivdForRecord, ltpAmbiguousTransport, ltpFrameRejected, ltpInitialState, ltpReduce, ltpUnexpectedEvent, messages, nonStandardDelimiters, orders, orphanComment, parseAstmDate, parseAstmRecords, parseChecksumHex, parseFramedAstm, parseReferenceRange, partialTimestamp, patient, primaryCode, profileQuirkApplied, query, readDelimiters, recognizeUniversalTestId, resolveProfileTransport, results, serializeAstmRecord, serializeAstmRecords, serializeField, serializeFramedAstm, setDefaultAstmProfile, splitEscapeAware, toChecksumHex, tokenizeHeader, tokenizeRecord, undefinedAbnormalFlag, undefinedResultStatus, uninterpretedQueryStatus, unitsAbsent, unknownEscapeSequence, unknownRecordType, unpairedEscapeCharacter, unparseableReferenceRange, unreadableRedeclaration };
4732
+ export { ALL_ASTM_WARNING_CODES, AMBIGUOUS_CODES, ACK as ASTM_ACK, ENQ as ASTM_ENQ, EOT as ASTM_EOT, NAK as ASTM_NAK, type AbnormalFlag, type AbnormalFlagCode, type AbnormalFlagMeaning, type AmbiguousCode, type AnyAstmWarningCode, AstmAmbiguousStreamError, type AstmDate, type AstmDatePrecision, type AstmField, type AstmFrame, AstmFrameEncodeError, type AstmFrameEncodeErrorCode, type AstmFramePosition, AstmFrameStrictError, type AstmFrameWarning, type AstmFraming, type AstmLivdWarning, type AstmLtpWarning, type AstmMessage, type AstmMessageClassification, type AstmMessageKind, AstmParseError, type AstmParseOptions, type AstmPosition, type AstmProfile, AstmProfileDefinitionError, type AstmProfileProvenance, type AstmQuirkMatch, type AstmQuirkTolerance, type AstmRecord, type AstmRecordInput, type AstmRecordWarning, AstmSerializeError, type AstmSerializeErrorCode, type AstmStreamMessage, AstmStrictError, CANONICAL_DELIMITERS, type CommentInput, type CommentRecord, type ComposeFramesOptions, type DecodeAstmFramesResult, type DefineAstmProfileOptions, type Delimiters, type DetectFramingOptions, type DetectFramingResult, FATAL_CODES, FRAME_WARNING_CODES, type FatalCode, type FrameChecksum, type FrameOptions, type FrameTerminator, type FrameWarningCode, type FramedAstmResult, type HeaderInput, type HeaderRecord, LIVD_WARNING_CODES, LTP_WARNING_CODES, type LivdAnnotation, type LivdCatalog, type LivdEntry, type LivdLookup, type LivdMapping, type LivdResult, type LivdWarningCode, type LtpAction, type LtpEvent, type LtpPhase, type LtpState, type LtpTransition, type LtpWarningCode, type ManufacturerRecord, type MessageInput, type OrderInput, type OrderRecord, type PatientInput, type PatientName, type PatientNameInput, type PatientRecord, type QueryInput, type QueryRecord, type ReferenceRange, type ReferenceRangeKind, type ResultInput, type ResultRecord, type ResultStatus, type ResultStatusCode, type ResultStatusMeaning, SAFETY_CRITICAL_CODES, type ScientificRecord, TOLERABLE_CODES, type TerminatorRecord, type UniversalTestId, type UniversalTestIdProvenance, type UnknownEscapeSink, type UnpairedEscapeSink, type UnsupportedRecord, VERSION, type VerbatimInput, WARNING_CODES, type WarningCode, ambiguousMessageKind, ambiguousValueSplit, applyAstmProfile, applyAstmProfileToWarnings, applyLivd, astmDateToLocalISO, astmProfiles, attachComments, buildAstmMessage, classifyMessage, comments, commentsFor, composeAstmFrames, computeChecksum, decodeAstmFrames, decodeEscapes, deepFreeze, defineAstmProfile, defineLivdCatalog, delimitersRedeclared, detectFraming, encodeComponent, fieldScalar, fieldsUnseparated, frameBadChecksum, frameOversize, frameSequenceGap, frameUnterminated, getAstmProfile, getDefaultAstmProfile, interpretAbnormalFlag, interpretResultStatus, isNonStandard, isSafetyCriticalCode, listAstmProfiles, livdAmbiguousMapping, livdUnmappedCode, lookupLivdForRecord, ltpAmbiguousTransport, ltpFrameRejected, ltpInitialState, ltpReduce, ltpUnexpectedEvent, messages, nonStandardDelimiters, orders, orphanComment, parseAstmDate, parseAstmRecords, parseChecksumHex, parseFramedAstm, parseReferenceRange, partialTimestamp, patient, primaryCode, profileQuirkApplied, query, readDelimiters, recognizeUniversalTestId, resolveProfileTransport, results, serializeAstmRecord, serializeAstmRecords, serializeField, serializeFramedAstm, setDefaultAstmProfile, splitEscapeAware, toChecksumHex, tokenizeHeader, tokenizeRecord, undefinedAbnormalFlag, undefinedResultStatus, uninterpretedQueryStatus, unitsAbsent, unknownEscapeSequence, unknownRecordType, unpairedEscapeCharacter, unparseableReferenceRange, unreadableRedeclaration };
package/dist/index.mjs CHANGED
@@ -2224,18 +2224,37 @@ var AstmFrameEncodeError = class extends Error {
2224
2224
  code;
2225
2225
  /** Index of the offending record within the input, when applicable. */
2226
2226
  recordIndex;
2227
+ /**
2228
+ * Position of the offending character within that record, when applicable:
2229
+ * its index in the string, never the character itself and never its code
2230
+ * point. Enough to find it in the caller's own data.
2231
+ */
2232
+ characterIndex;
2227
2233
  /** @internal */
2228
- constructor(message, recordIndex) {
2234
+ constructor(message, recordIndex, code = "ASTM_FRAME_EMPTY_RECORD", characterIndex) {
2229
2235
  super(message);
2230
2236
  this.name = "AstmFrameEncodeError";
2231
- this.code = "ASTM_FRAME_EMPTY_RECORD";
2237
+ this.code = code;
2232
2238
  if (recordIndex !== void 0) this.recordIndex = recordIndex;
2239
+ if (characterIndex !== void 0) this.characterIndex = characterIndex;
2233
2240
  }
2234
2241
  };
2235
- function toBytes(input) {
2242
+ var MAX_SINGLE_BYTE_CODE_POINT = 255;
2243
+ function toBytes(input, recordIndex) {
2236
2244
  if (typeof input !== "string") return input;
2237
2245
  const out = new Uint8Array(input.length);
2238
- for (let i = 0; i < input.length; i += 1) out[i] = input.charCodeAt(i) & 255;
2246
+ for (let i = 0; i < input.length; i += 1) {
2247
+ const code = input.charCodeAt(i);
2248
+ if (code > MAX_SINGLE_BYTE_CODE_POINT) {
2249
+ throw new AstmFrameEncodeError(
2250
+ "A record contains a character above U+00FF, which is not a single byte. Encode the record with the character encoding your instrument uses and pass the bytes.",
2251
+ recordIndex,
2252
+ "ASTM_FRAME_UNENCODABLE_CHARACTER",
2253
+ i
2254
+ );
2255
+ }
2256
+ out[i] = code;
2257
+ }
2239
2258
  return out;
2240
2259
  }
2241
2260
  function encodeFrame(text, frameNumber, isFinal) {
@@ -2252,7 +2271,7 @@ function composeAstmFrames(records, options = {}) {
2252
2271
  const out = [];
2253
2272
  let frameNumber = options.startFrameNumber ?? FIRST_FRAME_NUMBER;
2254
2273
  records.forEach((record, recordIndex) => {
2255
- const bytes = toBytes(record);
2274
+ const bytes = toBytes(record, recordIndex);
2256
2275
  if (bytes.length === 0) {
2257
2276
  throw new AstmFrameEncodeError(
2258
2277
  "Cannot frame an empty record: a frame must carry record bytes.",
@@ -2294,7 +2313,7 @@ function concatBytes3(chunks) {
2294
2313
  }
2295
2314
 
2296
2315
  // src/index.ts
2297
- var VERSION = "0.0.9";
2316
+ var VERSION = "0.0.10";
2298
2317
 
2299
2318
  export { ALL_ASTM_WARNING_CODES, AMBIGUOUS_CODES, ACK as ASTM_ACK, ENQ as ASTM_ENQ, EOT as ASTM_EOT, NAK as ASTM_NAK, AstmAmbiguousStreamError, AstmFrameEncodeError, AstmFrameStrictError, AstmParseError, AstmProfileDefinitionError, AstmSerializeError, AstmStrictError, CANONICAL_DELIMITERS, FATAL_CODES, FRAME_WARNING_CODES, LIVD_WARNING_CODES, LTP_WARNING_CODES, SAFETY_CRITICAL_CODES, TOLERABLE_CODES, VERSION, WARNING_CODES, ambiguousMessageKind, ambiguousValueSplit, applyAstmProfile, applyAstmProfileToWarnings, applyLivd, astmDateToLocalISO, astmProfiles, attachComments, buildAstmMessage, classifyMessage, comments, commentsFor, composeAstmFrames, computeChecksum, decodeAstmFrames, decodeEscapes, deepFreeze, defineAstmProfile, defineLivdCatalog, delimitersRedeclared, detectFraming, encodeComponent, fieldScalar, fieldsUnseparated, frameBadChecksum, frameOversize, frameSequenceGap, frameUnterminated, getAstmProfile, getDefaultAstmProfile, interpretAbnormalFlag, interpretResultStatus, isNonStandard, isSafetyCriticalCode, listAstmProfiles, livdAmbiguousMapping, livdUnmappedCode, lookupLivdForRecord, ltpAmbiguousTransport, ltpFrameRejected, ltpInitialState, ltpReduce, ltpUnexpectedEvent, messages, nonStandardDelimiters, orders, orphanComment, parseAstmDate, parseAstmRecords, parseChecksumHex, parseFramedAstm, parseReferenceRange, partialTimestamp, patient, primaryCode, profileQuirkApplied, query, readDelimiters, recognizeUniversalTestId, resolveProfileTransport, results, serializeAstmRecord, serializeAstmRecords, serializeField, serializeFramedAstm, setDefaultAstmProfile, splitEscapeAware, toChecksumHex, tokenizeHeader, tokenizeRecord, undefinedAbnormalFlag, undefinedResultStatus, uninterpretedQueryStatus, unitsAbsent, unknownEscapeSequence, unknownRecordType, unpairedEscapeCharacter, unparseableReferenceRange, unreadableRedeclaration };
2300
2319
  //# sourceMappingURL=index.mjs.map