Move docs/ package mirror into document-navigator plugin
Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
14
plugins/document-navigator/docs/foundation/barcode/README.md
Normal file
14
plugins/document-navigator/docs/foundation/barcode/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# `barcode`
|
||||
|
||||
1-D barcode generation and parsing.
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
## Packages in `barcode`
|
||||
|
||||
2 packages.
|
||||
|
||||
| Package | Description |
|
||||
|---|---|
|
||||
| [`@suaveplan/barcode`](./barcode/README.md) | Runtime-agnostic 1D barcode generation for seven symbologies — Code 128B, Code 39, EAN-13, EAN-8, UPC-A, UPC-E, and ITF. Outputs inline SVG strings and binary… |
|
||||
| [`@suaveplan/qrcode`](./qrcode/README.md) | QR code generation producing SVG, pixel matrix, terminal (Unicode blocks), and data URL representations. Implements QR code versions 1-10, error correction lev… |
|
||||
<!-- end:auto-docs -->
|
||||
@@ -0,0 +1 @@
|
||||
1-D barcode generation and parsing.
|
||||
@@ -0,0 +1,132 @@
|
||||
# @suaveplan/barcode - Barcode generation and parsing for common 1D symbologies: Code 128, Code 39, EAN-13, EAN-8, UPC-A, UPC-E, ITF. Outputs SVG strings and pixel arrays.
|
||||
|
||||
## Summary
|
||||
|
||||
Runtime-agnostic 1D barcode generation for seven symbologies — Code 128B, Code 39, EAN-13, EAN-8, UPC-A, UPC-E, and ITF. Outputs inline SVG strings and binary bar-pattern arrays with no canvas, no DOM, and no Node.js built-ins required, making it safe to use in Bun, Deno, edge runtimes, and browsers alike. Includes check-digit calculation, barcode validation, and human-readable text rendering. Use this package to generate product labels, shipping labels (ITF/GTIN-14), retail barcodes (EAN/UPC), and document barcodes (Code 128). For 2D barcodes (QR codes) use `@suaveplan/qrcode`. This package does not support barcode scanning/decoding from images — it is generation-only.
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
## Documentation tree
|
||||
|
||||
- [encoder](./src/core/encoder/encoder.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [encoder](./src/core/encoder/encoder.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [validator](./src/core/validator/validator.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [validator](./src/core/validator/validator.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [errors](./src/errors/barcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [barcode-error](./src/errors/barcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [code128](./src/symbologies/code128.md) — Implements Code 128 Subset B encoding for the full printable ASCII range (characters 32–127). This module produces a bi…
|
||||
- [code39](./src/symbologies/code39.md) — Implements Code 39 barcode encoding for the standard 43-character set: digits 0–9, uppercase letters A–Z, and the speci…
|
||||
- [ean13](./src/symbologies/ean13.md) — Implements EAN-13 (International Article Number, 13-digit variant) barcode encoding following the ISO/IEC 15420 and GS1…
|
||||
- [ean8](./src/symbologies/ean8.md) — Implements EAN-8 barcode encoding for small retail packages where space constraints make EAN-13 impractical. EAN-8 enco…
|
||||
- [itf](./src/symbologies/itf.md) — Implements ITF (Interleaved 2 of 5) barcode encoding for numeric-only data. ITF is widely used in logistics, shipping,…
|
||||
- [upca](./src/symbologies/upca.md) — Implements UPC-A barcode encoding and validation. UPC-A is the primary barcode format used in North American retail, en…
|
||||
- [upce](./src/symbologies/upce.md) — Implements UPC-E barcode encoding for the compressed 6-digit UPC symbology used on small retail packages where space fo…
|
||||
<!-- end:auto-docs --> - [encoder](./src/core/encoder/encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [validator](./src/core/validator/validator.md) — <!-- begin:auto-docs --> _(no submodules)_- [validator](./src/core/validator/validator.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/barcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [barcode-error](./src/errors/barcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [code128](./src/symbologies/code128.md) — Implements Code 128 Subset B encoding for the full printable ASCII range (characters 32–127). This module produces a bi…
|
||||
- [code39](./src/symbologies/code39.md) — Implements Code 39 barcode encoding for the standard 43-character set: digits 0–9, uppercase letters A–Z, and the speci…
|
||||
- [ean13](./src/symbologies/ean13.md) — Implements EAN-13 (International Article Number, 13-digit variant) barcode encoding following the ISO/IEC 15420 and GS1…
|
||||
- [ean8](./src/symbologies/ean8.md) — Implements EAN-8 barcode encoding for small retail packages where space constraints make EAN-13 impractical. EAN-8 enco…
|
||||
- [itf](./src/symbologies/itf.md) — Implements ITF (Interleaved 2 of 5) barcode encoding for numeric-only data. ITF is widely used in logistics, shipping,…
|
||||
- [upca](./src/symbologies/upca.md) — Implements UPC-A barcode encoding and validation. UPC-A is the primary barcode format used in North American retail, en…
|
||||
- [upce](./src/symbologies/upce.md) — Implements UPC-E barcode encoding for the compressed 6-digit UPC symbology used on small retail packages where space fo…
|
||||
- [encoder](./src/core/encoder/encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [validator](./src/core/validator/validator.md) — <!-- begin:auto-docs --> _(no submodules)_- [validator](./src/core/validator/validator.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/barcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [barcode-error](./src/errors/barcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [code128](./src/symbologies/code128.md) — Implements Code 128 Subset B encoding for the full printable ASCII range (characters 32–127). This module produces a bi…
|
||||
- [code39](./src/symbologies/code39.md) — Implements Code 39 barcode encoding for the standard 43-character set: digits 0–9, uppercase letters A–Z, and the speci…
|
||||
- [ean13](./src/symbologies/ean13.md) — Implements EAN-13 (International Article Number, 13-digit variant) barcode encoding following the ISO/IEC 15420 and GS1…
|
||||
- [ean8](./src/symbologies/ean8.md) — Implements EAN-8 barcode encoding for small retail packages where space constraints make EAN-13 impractical. EAN-8 enco…
|
||||
- [itf](./src/symbologies/itf.md) — Implements ITF (Interleaved 2 of 5) barcode encoding for numeric-only data. ITF is widely used in logistics, shipping,…
|
||||
- [upca](./src/symbologies/upca.md) — Implements UPC-A barcode encoding and validation. UPC-A is the primary barcode format used in North American retail, en…
|
||||
- [upce](./src/symbologies/upce.md) — Implements UPC-E barcode encoding for the compressed 6-digit UPC symbology used on small retail packages where space fo…
|
||||
- [encoder](./src/core/encoder/encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [validator](./src/core/validator/validator.md) — <!-- begin:auto-docs --> _(no submodules)_- [validator](./src/core/validator/validator.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/barcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [barcode-error](./src/errors/barcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [code128](./src/symbologies/code128.md) — Implements Code 128 Subset B encoding for the full printable ASCII range (characters 32–127). This module produces a bi…
|
||||
- [code39](./src/symbologies/code39.md) — Implements Code 39 barcode encoding for the standard 43-character set: digits 0–9, uppercase letters A–Z, and the speci…
|
||||
- [ean13](./src/symbologies/ean13.md) — Implements EAN-13 (International Article Number, 13-digit variant) barcode encoding following the ISO/IEC 15420 and GS1…
|
||||
- [ean8](./src/symbologies/ean8.md) — Implements EAN-8 barcode encoding for small retail packages where space constraints make EAN-13 impractical. EAN-8 enco…
|
||||
- [itf](./src/symbologies/itf.md) — Implements ITF (Interleaved 2 of 5) barcode encoding for numeric-only data. ITF is widely used in logistics, shipping,…
|
||||
- [upca](./src/symbologies/upca.md) — Implements UPC-A barcode encoding and validation. UPC-A is the primary barcode format used in North American retail, en…
|
||||
- [upce](./src/symbologies/upce.md) — Implements UPC-E barcode encoding for the compressed 6-digit UPC symbology used on small retail packages where space fo…
|
||||
- [encoder](./src/core/encoder/encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [validator](./src/core/validator/validator.md) — <!-- begin:auto-docs --> _(no submodules)_ - [validator](./src/core/validator/validator.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/barcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_ - [barcode-error](./src/errors/barcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [code128](./src/symbologies/code128.md) — Implements Code 128 Subset B encoding for the full printable ASCII range (characters 32–127). This module produces a bi…
|
||||
- [code39](./src/symbologies/code39.md) — Implements Code 39 barcode encoding for the standard 43-character set: digits 0–9, uppercase letters A–Z, and the speci…
|
||||
- [ean13](./src/symbologies/ean13.md) — Implements EAN-13 (International Article Number, 13-digit variant) barcode encoding following the ISO/IEC 15420 and GS1…
|
||||
- [ean8](./src/symbologies/ean8.md) — Implements EAN-8 barcode encoding for small retail packages where space constraints make EAN-13 impractical. EAN-8 enco…
|
||||
- [itf](./src/symbologies/itf.md) — Implements ITF (Interleaved 2 of 5) barcode encoding for numeric-only data. ITF is widely used in logistics, shipping,…
|
||||
- [upca](./src/symbologies/upca.md) — Implements UPC-A barcode encoding and validation. UPC-A is the primary barcode format used in North American retail, en…
|
||||
- [upce](./src/symbologies/upce.md) — Implements UPC-E barcode encoding for the compressed 6-digit UPC symbology used on small retail packages where space fo…
|
||||
|
||||
## Symbologies
|
||||
|
||||
| Symbology | Key | Description |
|
||||
|-----------|-----|-------------|
|
||||
| Code 128B | `code128` | ASCII 32–127; variable length; most versatile 1D format |
|
||||
| Code 39 | `code39` | 0–9, A–Z, special chars; industrial/logistics |
|
||||
| EAN-13 | `ean13` | 13-digit retail standard (ISBN-13, ISSN-13) |
|
||||
| EAN-8 | `ean8` | 8-digit compact retail for small packages |
|
||||
| UPC-A | `upca` | 12-digit North American retail |
|
||||
| UPC-E | `upce` | 8-digit compressed UPC-A for small packages |
|
||||
| ITF | `itf` | Interleaved 2 of 5; even-digit numeric; logistics/GTIN-14 |
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
bun add @suaveplan/barcode
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```ts
|
||||
import { encode } from "@suaveplan/barcode";
|
||||
|
||||
const result = encode("Hello World", "code128");
|
||||
console.log(result.svg); // <svg ...>...</svg>
|
||||
console.log(result.width); // pixel width
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### `encode(data, symbology, options?): BarcodeResult`
|
||||
|
||||
Main encoding function. Dispatches to the per-symbology encoder and renders an SVG.
|
||||
|
||||
```ts
|
||||
import { encode } from "@suaveplan/barcode";
|
||||
|
||||
const result = encode("5901234123457", "ean13", {
|
||||
width: 3, // bar width multiplier (default 2)
|
||||
height: 80, // bar height in pixels (default 100)
|
||||
margin: 15, // quiet zone (default 10)
|
||||
includeText: true, // render human-readable text (default true)
|
||||
color: "#000000",
|
||||
background: "#ffffff",
|
||||
});
|
||||
```
|
||||
|
||||
### `validateBarcode(data, symbology): boolean`
|
||||
|
||||
```ts
|
||||
import { validateBarcode } from "@suaveplan/barcode";
|
||||
validateBarcode("5901234123457", "ean13"); // true
|
||||
```
|
||||
|
||||
### `calculateCheckDigit(data, symbology): string`
|
||||
|
||||
```ts
|
||||
import { calculateCheckDigit } from "@suaveplan/barcode";
|
||||
calculateCheckDigit("590123412345", "ean13"); // "7"
|
||||
```
|
||||
|
||||
### `parse(data, symbology): ParseResult`
|
||||
|
||||
```ts
|
||||
import { parse } from "@suaveplan/barcode";
|
||||
const r = parse("5901234123457", "ean13");
|
||||
// { symbology: "ean13", data: "...", valid: true, checkDigit: "7" }
|
||||
```
|
||||
|
||||
## Module Docs
|
||||
|
||||
- [`src/errors/barcode-error.md`](src/errors/barcode-error.md) — Error class and code registry
|
||||
- [`src/symbologies/code128.md`](src/symbologies/code128.md) — Code 128B encoding
|
||||
- [`src/symbologies/code39.md`](src/symbologies/code39.md) — Code 39 encoding
|
||||
- [`src/symbologies/ean13.md`](src/symbologies/ean13.md) — EAN-13 encoding
|
||||
- [`src/symbologies/ean8.md`](src/symbologies/ean8.md) — EAN-8 encoding
|
||||
- [`src/symbologies/upca.md`](src/symbologies/upca.md) — UPC-A encoding
|
||||
- [`src/symbologies/upce.md`](src/symbologies/upce.md) — UPC-E encoding
|
||||
- [`src/symbologies/itf.md`](src/symbologies/itf.md) — ITF encoding
|
||||
- [`src/core/encoder/encoder.md`](src/core/encoder/encoder.md) — Central encoder and SVG renderer
|
||||
- [`src/core/validator/validator.md`](src/core/validator/validator.md) — Validation and parsing facade
|
||||
@@ -0,0 +1,87 @@
|
||||
# encoder
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Provides the central barcode encoding pipeline for `@suaveplan/barcode`. It dispatches input data to the correct per-symbology encoder, then renders the resulting binary bar pattern into a complete, self-contained SVG string. The encoder is the primary entry point for most consumer use cases — callers only need `encode(data, symbology, options)`.
|
||||
|
||||
## Features
|
||||
|
||||
- `encode(data, symbology, options?)` — full pipeline: dispatch → binary encoding → SVG rendering.
|
||||
- `renderSvg(encoded, data, opts)` — exposed for testing and advanced pipelines that need SVG rendering without re-encoding.
|
||||
- Run-length encoding of consecutive bits for compact `<rect>` output.
|
||||
- XML-safe text rendering via `escapeXml`.
|
||||
- Configurable bar width, bar height, margin, text inclusion, and colours via `BarcodeOptions`.
|
||||
- Defaults: width=2, height=100, margin=10, includeText=true, color=#000000, background=#ffffff.
|
||||
- Throws `BarcodeError` with stable codes on invalid input or unsupported symbology.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { encode } from "@suaveplan/barcode/encoder";
|
||||
|
||||
const result = encode("Hello World", "code128");
|
||||
console.log(result.svg); // complete <svg>...</svg> string
|
||||
console.log(result.width); // total pixel width
|
||||
console.log(result.encoded); // binary bar pattern
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { encode, renderSvg } from "@suaveplan/barcode/encoder";
|
||||
|
||||
// Custom rendering options
|
||||
const result = encode("5901234123457", "ean13", {
|
||||
width: 3,
|
||||
height: 80,
|
||||
margin: 15,
|
||||
includeText: false,
|
||||
color: "#1a1a2e",
|
||||
background: "#e8f4f8",
|
||||
});
|
||||
|
||||
// Separate render pass with modified options
|
||||
const customSvg = renderSvg(result.encoded, result.data, {
|
||||
width: 1,
|
||||
height: 50,
|
||||
margin: 5,
|
||||
includeText: true,
|
||||
color: "#000000",
|
||||
background: "#ffffff",
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `encode(data: string, symbology: BarcodeSymbology, options?: BarcodeOptions): BarcodeResult`
|
||||
|
||||
Main entry point for barcode generation.
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `data` | `string` | Raw data to encode |
|
||||
| `symbology` | `BarcodeSymbology` | Target symbology (`"code128"`, `"ean13"`, etc.) |
|
||||
| `options` | `BarcodeOptions` | Optional rendering configuration |
|
||||
|
||||
Returns `BarcodeResult` with fields: `symbology`, `data`, `encoded`, `svg`, `width`, `height`.
|
||||
|
||||
**Throws** `BarcodeError(ENCODE_FAILED)` if the underlying encoder fails, or `BarcodeError(UNSUPPORTED_SYMBOLOGY)` for unknown symbology values.
|
||||
|
||||
### `renderSvg(encoded: string, data: string, opts: Required<BarcodeOptions>): string`
|
||||
|
||||
Renders a pre-computed binary string to SVG.
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------|
|
||||
| `encoded` | Binary string: `'1'` = bar, `'0'` = space |
|
||||
| `data` | Human-readable label text (rendered below bars when `includeText` is true) |
|
||||
| `opts` | Fully-resolved options (no optional fields) |
|
||||
|
||||
Returns a complete `<svg>` element string suitable for embedding in HTML or writing to a file.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Run-length encoding groups consecutive identical bits before emitting `<rect>` elements, reducing the number of SVG elements for long runs (e.g. quiet zones, wide bars). Text rendering uses `escapeXml` to prevent SVG injection when the data string contains `<`, `>`, `"`, `'`, or `&`. The background rectangle is always rendered first so bar rectangles appear on top. The total height includes bar height + optional text height (14px) + two margin widths (top and bottom).
|
||||
@@ -0,0 +1,78 @@
|
||||
# validator
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Provides cross-symbology barcode validation, check-digit calculation, and structured parsing for the `@suaveplan/barcode` package. While each symbology module exposes its own `validate` function, this module serves as a unified facade so callers can perform validation without needing to import individual symbology modules. It also exposes a `calculateCheckDigit` utility for EAN/UPC families and a `parse` function that returns a structured result including validity status and extracted check digit.
|
||||
|
||||
## Features
|
||||
|
||||
- `validateBarcode(data, symbology)` — dispatches to per-symbology validator, returns `boolean`.
|
||||
- `calculateCheckDigit(data, symbology)` — GS1 check digit for EAN-13, EAN-8, and UPC-A.
|
||||
- `parse(data, symbology)` — returns `ParseResult` with `valid`, `checkDigit` (where applicable).
|
||||
- Exhaustive switch guards with `never` type for compile-time completeness.
|
||||
- Throws `BarcodeError` with stable codes for unsupported symbologies or invalid input.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { validateBarcode, calculateCheckDigit } from "@suaveplan/barcode/validator";
|
||||
|
||||
const valid = validateBarcode("5901234123457", "ean13"); // true
|
||||
const check = calculateCheckDigit("590123412345", "ean13"); // "7"
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { parse } from "@suaveplan/barcode/validator";
|
||||
|
||||
const result = parse("5901234123457", "ean13");
|
||||
// {
|
||||
// symbology: "ean13",
|
||||
// data: "5901234123457",
|
||||
// valid: true,
|
||||
// checkDigit: "7"
|
||||
// }
|
||||
|
||||
const invalid = parse("5901234123458", "ean13");
|
||||
// { valid: false, checkDigit: "8" }
|
||||
|
||||
// Code 128 parse — no check digit extracted
|
||||
const code128 = parse("HELLO", "code128");
|
||||
// { symbology: "code128", data: "HELLO", valid: true }
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `validateBarcode(data: string, symbology: BarcodeSymbology): boolean`
|
||||
|
||||
Dispatches to the appropriate per-symbology `validate` function. Returns `true` if `data` is valid for `symbology`. Does not throw for validation failures (only throws for unsupported symbology).
|
||||
|
||||
### `calculateCheckDigit(data: string, symbology: 'ean13' | 'ean8' | 'upca'): string`
|
||||
|
||||
Computes the check digit for EAN/UPC symbologies.
|
||||
|
||||
| Parameter | Requirement |
|
||||
|-----------|-------------|
|
||||
| `data` | 12 digits for `ean13`/`upca`, 7 digits for `ean8` |
|
||||
| `symbology` | Must be `'ean13'`, `'ean8'`, or `'upca'` |
|
||||
|
||||
Returns check digit as a `string` character `'0'`–`'9'`. **Throws** `BarcodeError(INVALID_DATA)` for non-numeric input or wrong digit count.
|
||||
|
||||
### `parse(data: string, symbology: BarcodeSymbology): ParseResult`
|
||||
|
||||
Returns a structured `ParseResult`:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `symbology` | `BarcodeSymbology` | The symbology used |
|
||||
| `data` | `string` | The input data string |
|
||||
| `valid` | `boolean` | Whether data is valid for the symbology |
|
||||
| `checkDigit` | `string \| undefined` | Last digit for EAN/UPC types; absent for Code 128/39/ITF |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The `parse` function extracts the check digit by position convention: last digit of EAN-13 (13th), EAN-8 (8th), UPC-A (12th), and UPC-E (8th). The `checkDigit` field is only present when the data string has the expected length. Exhaustive switch statements with `never` fall-through guards ensure TypeScript enforces full coverage when new symbologies are added to the `BarcodeSymbology` union type.
|
||||
@@ -0,0 +1,82 @@
|
||||
# barcode-error
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Provides the structured error class and stable error-code registry used throughout the `@suaveplan/barcode` package. As a leaf dependency with no `@suaveplan/error` runtime dependency, this module is fully self-contained while preserving the same structural contract (named `code` field, typed constants) expected by consumers of the wider Suaveplan error ecosystem.
|
||||
|
||||
## Features
|
||||
|
||||
- `BARCODE_CODES` — an `as const` object of stable string codes, suitable for `switch`/`if` guards without importing magic numbers.
|
||||
- `BarcodeCode` — union type derived from `BARCODE_CODES` so callers get exhaustive checking.
|
||||
- `BarcodeError extends Error` — standard JS error subclass with `name = "BarcodeError"` and a typed `code` field; fully serialisable across `structuredClone`, `JSON.stringify`, and Worker boundaries.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { BarcodeError, BARCODE_CODES } from "@suaveplan/barcode/errors";
|
||||
|
||||
throw new BarcodeError(
|
||||
"EAN-13 requires exactly 13 digits",
|
||||
BARCODE_CODES.INVALID_DATA,
|
||||
);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { BarcodeError, BARCODE_CODES, type BarcodeCode } from "@suaveplan/barcode/errors";
|
||||
|
||||
function handleBarcodeError(err: unknown): void {
|
||||
if (err instanceof BarcodeError) {
|
||||
switch (err.code) {
|
||||
case BARCODE_CODES.INVALID_DATA:
|
||||
console.error("Bad input:", err.message);
|
||||
break;
|
||||
case BARCODE_CODES.UNSUPPORTED_SYMBOLOGY:
|
||||
console.error("Unknown symbology:", err.message);
|
||||
break;
|
||||
case BARCODE_CODES.ENCODE_FAILED:
|
||||
console.error("Encoding failed:", err.message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `BARCODE_CODES`
|
||||
|
||||
`const` object with three keys:
|
||||
|
||||
| Key | Value |
|
||||
|-----|-------|
|
||||
| `INVALID_DATA` | `"BARCODE.INVALID_DATA"` |
|
||||
| `UNSUPPORTED_SYMBOLOGY` | `"BARCODE.UNSUPPORTED_SYMBOLOGY"` |
|
||||
| `ENCODE_FAILED` | `"BARCODE.ENCODE_FAILED"` |
|
||||
|
||||
### `BarcodeCode`
|
||||
|
||||
Derived union type: `"BARCODE.INVALID_DATA" | "BARCODE.UNSUPPORTED_SYMBOLOGY" | "BARCODE.ENCODE_FAILED"`.
|
||||
|
||||
### `BarcodeError`
|
||||
|
||||
```ts
|
||||
class BarcodeError extends Error {
|
||||
readonly code: BarcodeCode;
|
||||
constructor(message: string, code: BarcodeCode);
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `name` | `"BarcodeError"` | Set in constructor; identifies error type. |
|
||||
| `code` | `BarcodeCode` | Stable machine-readable code for programmatic handling. |
|
||||
| `message` | `string` | Human-readable description of the problem. |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The module is deliberately framework-free and has zero runtime imports. The `as const` assertion on `BARCODE_CODES` gives TypeScript narrowing without any extra overhead. Extending the native `Error` class means `instanceof BarcodeError` checks work across realm boundaries (Worker ↔ main thread) as long as the same class reference is used. The `code` field is marked `readonly` to prevent accidental mutation after construction.
|
||||
@@ -0,0 +1,68 @@
|
||||
# code128
|
||||
|
||||
## Purpose
|
||||
|
||||
Implements Code 128 Subset B encoding for the full printable ASCII range (characters 32–127). This module produces a binary bar-pattern string that faithfully represents the ISO/IEC 15417 standard: start symbol, per-character 11-bit patterns from the Code 128B table, mod-103 check symbol, and the 13-bit stop symbol. It is the most versatile 1D symbology in common use and handles arbitrary printable text without requiring special character-set switching.
|
||||
|
||||
## Features
|
||||
|
||||
- Full 96-entry Code 128B character table (ASCII 32–127).
|
||||
- `encode(data)` — returns a binary `'0'/'1'` string ready for SVG rendering.
|
||||
- `validate(data)` — pre-flight check before encoding, returns `boolean`.
|
||||
- `checkValue(data)` — computes the raw numeric check value (0–102) independently.
|
||||
- Throws `BarcodeError` with stable codes on invalid input or encoding failure.
|
||||
- Zero external dependencies; pure computation.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { encode, validate } from "@suaveplan/barcode/symbologies";
|
||||
|
||||
if (validate("Hello-123")) {
|
||||
const bits = encode("Hello-123");
|
||||
console.log(bits.startsWith("11010010000")); // true — Code B start symbol
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { encode, checkValue } from "@suaveplan/barcode/symbologies";
|
||||
|
||||
// Compute check digit independently for audit purposes
|
||||
const cv = checkValue("ABC");
|
||||
console.log(`Check value: ${cv}`); // deterministic numeric 0–102
|
||||
|
||||
// Encode and inspect structure
|
||||
const bits = encode("ABC");
|
||||
const startSymbol = bits.slice(0, 11); // "11010010000" (START B)
|
||||
const stopSymbol = bits.slice(-13); // "1100011101011" (STOP)
|
||||
console.log(startSymbol, stopSymbol);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `validate(data: string): boolean`
|
||||
|
||||
Returns `true` if every character in `data` has a code point in the range 32–127 (inclusive) and `data.length > 0`. Returns `false` otherwise. Does not throw.
|
||||
|
||||
### `encode(data: string): string`
|
||||
|
||||
Encodes `data` into a binary string using Code 128 Subset B.
|
||||
|
||||
| Segment | Description |
|
||||
|---------|-------------|
|
||||
| START B | `11010010000` |
|
||||
| Data chars | Each character → 11-bit table lookup |
|
||||
| Check symbol | Derived from mod-103 weighted sum |
|
||||
| STOP | `1100011101011` |
|
||||
|
||||
**Throws** `BarcodeError(BARCODE_CODES.INVALID_DATA)` if any character is outside ASCII 32–127.
|
||||
|
||||
### `checkValue(data: string): number`
|
||||
|
||||
Returns the integer check value (0–102) computed as `(START_B_VALUE + Σ tableIndex_i × (i+1)) mod 103`. Useful for verification without full encode overhead.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The 108-entry table is declared as a `readonly string[]` constant. Characters in Subset B are indexed as `charCode - 32`, so ASCII space (32) → index 0, `~` (126) → index 94, DEL (127) → index 95. Indices 96–107 cover special function/control values. The check digit accumulates `(i + 1)` as the positional weight (1-based), consistent with the ISO spec. The stop symbol is a fixed 13-bit pattern not present in the main table (it has a different width) and is simply concatenated verbatim.
|
||||
@@ -0,0 +1,63 @@
|
||||
# code39
|
||||
|
||||
## Purpose
|
||||
|
||||
Implements Code 39 barcode encoding for the standard 43-character set: digits 0–9, uppercase letters A–Z, and the special characters space, hyphen, period, dollar, slash, plus, and percent. Code 39 is a variable-length, self-checking, discrete symbology widely used in industrial and logistics applications. This module auto-upper-cases input for ergonomic developer experience and produces a binary bar-pattern string ready for SVG rendering.
|
||||
|
||||
## Features
|
||||
|
||||
- `encode(data)` — returns a binary `'0'/'1'` string with START, payload, inter-character gaps, and STOP symbols.
|
||||
- `validate(data)` — checks every character against the legal Code 39 set; returns `boolean`.
|
||||
- Auto-upper-case normalisation during encoding.
|
||||
- Narrow inter-character gap (`'0'`) inserted between every symbol pair.
|
||||
- Throws `BarcodeError` with stable codes on invalid input.
|
||||
- Zero external dependencies.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { encode, validate } from "@suaveplan/barcode/symbologies";
|
||||
|
||||
if (validate("HELLO-123")) {
|
||||
const bits = encode("HELLO-123");
|
||||
// bits begins with Code 39 start (*) pattern
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { encode } from "@suaveplan/barcode/symbologies";
|
||||
|
||||
// Lower-case is automatically normalised to upper-case
|
||||
const bits = encode("hello world");
|
||||
// Equivalent to encode("HELLO WORLD")
|
||||
|
||||
// Inspect start/stop boundaries
|
||||
const startPattern = "100101101101";
|
||||
console.log(bits.startsWith(startPattern)); // true
|
||||
console.log(bits.endsWith(startPattern)); // true (same * symbol for stop)
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `validate(data: string): boolean`
|
||||
|
||||
Returns `true` if every character in `data.toUpperCase()` exists in the Code 39 character set (0–9, A–Z, space, `-`, `.`, `$`, `/`, `+`, `%`) and `data.length > 0`. The `*` start/stop character is not valid in payloads. Returns `false` without throwing.
|
||||
|
||||
### `encode(data: string): string`
|
||||
|
||||
Encodes `data` into a binary string.
|
||||
|
||||
| Segment | Description |
|
||||
|---------|-------------|
|
||||
| START | `*` symbol pattern |
|
||||
| Gap | Narrow `'0'` inter-character gap |
|
||||
| Data | Each character → 12-bit lookup + narrow gap |
|
||||
| STOP | `*` symbol pattern (no trailing gap) |
|
||||
|
||||
Each character produces a 12-bit pattern (9 element bits + 3 implicit bar/space transitions from narrow/wide encoding). **Throws** `BarcodeError(BARCODE_CODES.INVALID_DATA)` if any character is not in the allowed set.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Code 39 patterns in this implementation use a compact 12-character binary representation where narrow elements are `'0'` and wide elements are `'1'`. Pattern ordering follows the standard bar-space-bar-space-bar-space-bar-space-bar sequence. Inter-character gaps are appended after each symbol including START, but not after STOP. Input is normalised to upper case before validation so lowercase ASCII letters map correctly.
|
||||
@@ -0,0 +1,77 @@
|
||||
# ean13
|
||||
|
||||
## Purpose
|
||||
|
||||
Implements EAN-13 (International Article Number, 13-digit variant) barcode encoding following the ISO/IEC 15420 and GS1 specifications. EAN-13 is the global standard for retail product identification and is recognised by virtually all point-of-sale systems worldwide. This module handles the full encoding pipeline: check digit computation, first-digit parity selection, L-code/G-code left-side encoding, R-code right-side encoding, and assembly of guard bars.
|
||||
|
||||
## Features
|
||||
|
||||
- `encode(data)` — accepts 12 or 13 digit strings; auto-appends check digit for 12-digit input.
|
||||
- `validate(data)` — verifies length, digit-only content, and check digit correctness.
|
||||
- `computeCheckDigit(digits)` — standalone GS1 Luhn-weight check digit calculator (weights 1 and 3).
|
||||
- Full 3-zone encoding: left guard `101`, 6 L/G-code digits, centre guard `01010`, 6 R-code digits, right guard `101`.
|
||||
- First-digit parity table derived from GS1 specification.
|
||||
- Throws `BarcodeError` with stable codes on invalid input.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { encode, validate } from "@suaveplan/barcode/symbologies";
|
||||
|
||||
// Validate a known EAN-13
|
||||
console.log(validate("5901234123457")); // true
|
||||
|
||||
// Encode (auto-computes check if 12 digits provided)
|
||||
const bits = encode("590123412345");
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { encode, computeCheckDigit } from "@suaveplan/barcode/symbologies";
|
||||
|
||||
// Compute and verify a check digit independently
|
||||
const digits = [5, 9, 0, 1, 2, 3, 4, 1, 2, 3, 4, 5];
|
||||
const check = computeCheckDigit(digits);
|
||||
console.log(check); // 7
|
||||
|
||||
// Encode a full 13-digit code
|
||||
const bits = encode("5901234123457");
|
||||
// Structure: 101 + 6×7-bit left + 01010 + 6×7-bit right + 101
|
||||
console.log(bits.startsWith("101")); // true
|
||||
console.log(bits.length); // 95
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `computeCheckDigit(digits: readonly number[]): number`
|
||||
|
||||
Computes the EAN/UPC Luhn check digit for an array of 12 digit values (0–9). Applies alternating weights 1 and 3 starting with weight 1 for the first digit, sums the products, and returns `(10 - (sum % 10)) % 10`.
|
||||
|
||||
### `validate(data: string): boolean`
|
||||
|
||||
Returns `true` if:
|
||||
|
||||
- `data` matches `/^\d{13}$/`
|
||||
- the 13th digit equals `computeCheckDigit(first 12 digits)`
|
||||
|
||||
Returns `false` without throwing.
|
||||
|
||||
### `encode(data: string): string`
|
||||
|
||||
Encodes an EAN-13 barcode into a binary string.
|
||||
|
||||
| Segment | Width | Description |
|
||||
|---------|-------|-------------|
|
||||
| Left guard | 3 | `101` |
|
||||
| Left digits 1–6 | 42 | 6 × 7-bit L/G-code per first-digit parity |
|
||||
| Centre guard | 5 | `01010` |
|
||||
| Right digits 7–12 | 42 | 6 × 7-bit R-code |
|
||||
| Right guard | 3 | `101` |
|
||||
| **Total** | **95** | |
|
||||
|
||||
Accepts 12-digit strings (check digit auto-appended) or 13-digit strings. **Throws** `BarcodeError(BARCODE_CODES.INVALID_DATA)` for non-digit input or wrong length.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The first-digit parity table follows the GS1 General Specifications. L-codes have odd parity (start with `0`), G-codes have even parity (bitwise complement of R-code, start with `0`), and R-codes have even parity (start with `1`). The first digit of EAN-13 is encoded implicitly in the left-side parity pattern — it does not appear as a bar itself. The total encoded width is exactly 95 modules.
|
||||
@@ -0,0 +1,61 @@
|
||||
# ean8
|
||||
|
||||
## Purpose
|
||||
|
||||
Implements EAN-8 barcode encoding for small retail packages where space constraints make EAN-13 impractical. EAN-8 encodes 8 digits (7 data + 1 check digit) and uses the same GS1 Luhn check-digit algorithm as EAN-13 but with a simplified left-side encoding (all L-code, no G-code parity switching). This module delegates check-digit computation to the `ean13` module to avoid duplication.
|
||||
|
||||
## Features
|
||||
|
||||
- `encode(data)` — accepts 7 or 8 digit strings; auto-appends check digit for 7-digit input.
|
||||
- `validate(data)` — verifies 8-digit format and check digit correctness.
|
||||
- Left guard `101`, centre guard `01010`, right guard `101`.
|
||||
- Left 4 digits encoded in L-code; right 4 digits in R-code.
|
||||
- Throws `BarcodeError` with stable codes on invalid input.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { encode, validate } from "@suaveplan/barcode/symbologies";
|
||||
|
||||
console.log(validate("96385074")); // true
|
||||
|
||||
const bits = encode("9638507"); // auto-appends check digit 4
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { encode } from "@suaveplan/barcode/symbologies";
|
||||
|
||||
// Encode with explicit 8-digit input
|
||||
const bits = encode("96385074");
|
||||
|
||||
// Structure: 101 + 4×7-bit L-code + 01010 + 4×7-bit R-code + 101
|
||||
console.log(bits.startsWith("101")); // true
|
||||
console.log(bits.length); // 67
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `validate(data: string): boolean`
|
||||
|
||||
Returns `true` if `data` matches `/^\d{8}$/` and the 8th digit equals the computed check digit for the first 7. Returns `false` otherwise.
|
||||
|
||||
### `encode(data: string): string`
|
||||
|
||||
Encodes an EAN-8 barcode into a binary string.
|
||||
|
||||
| Segment | Width | Description |
|
||||
|---------|-------|-------------|
|
||||
| Left guard | 3 | `101` |
|
||||
| Left digits 1–4 | 28 | 4 × 7-bit L-code |
|
||||
| Centre guard | 5 | `01010` |
|
||||
| Right digits 5–8 | 28 | 4 × 7-bit R-code |
|
||||
| Right guard | 3 | `101` |
|
||||
| **Total** | **67** | |
|
||||
|
||||
Accepts 7-digit strings (check digit auto-appended) or 8-digit strings. **Throws** `BarcodeError(BARCODE_CODES.INVALID_DATA)` for non-digit input or wrong length.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
EAN-8 uses L-code for all left-side digits (no first-digit parity switching). This simplification is valid because the 8-digit format carries enough data in the guard structure to maintain optical orientation detection. The L-code and R-code tables in this module are duplicated from `ean13.ts` rather than imported to keep the module self-contained for bundle-splitting scenarios where only EAN-8 is used.
|
||||
@@ -0,0 +1,60 @@
|
||||
# itf
|
||||
|
||||
## Purpose
|
||||
|
||||
Implements ITF (Interleaved 2 of 5) barcode encoding for numeric-only data. ITF is widely used in logistics, shipping, and inventory applications because it achieves high density by interleaving two digit streams — one encoded in bars and one in spaces — simultaneously. This module encodes digit pairs into alternating bar/space elements following the ISO/IEC 16390 standard, with start and stop guards.
|
||||
|
||||
## Features
|
||||
|
||||
- `encode(data)` — encodes an even-length digit string into a binary bar pattern.
|
||||
- `validate(data)` — verifies digit-only content and even length requirement.
|
||||
- Narrow element = 1 module, wide element = 3 modules (3:1 ratio).
|
||||
- Start guard `0000`, stop guard `100`.
|
||||
- Each digit pair interleaved: 5 bar elements (first digit) × 5 space elements (second digit).
|
||||
- Throws `BarcodeError` with stable codes on invalid input.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { encode, validate } from "@suaveplan/barcode/symbologies";
|
||||
|
||||
console.log(validate("12345678")); // true
|
||||
console.log(validate("1234567")); // false — odd length
|
||||
|
||||
const bits = encode("12345678");
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { encode } from "@suaveplan/barcode/symbologies";
|
||||
|
||||
// Encode a 14-digit GTIN (common ITF-14 use case)
|
||||
const bits = encode("12345678901231");
|
||||
|
||||
// ITF structure: 0000 (start) + pairs + 100 (stop)
|
||||
console.log(bits.startsWith("0000")); // true
|
||||
console.log(bits.endsWith("100")); // true
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `validate(data: string): boolean`
|
||||
|
||||
Returns `true` if `data` matches `/^\d+$/` and `data.length` is even and greater than zero. Returns `false` without throwing.
|
||||
|
||||
### `encode(data: string): string`
|
||||
|
||||
Encodes ITF data into a binary string. Processes digits in pairs: the first digit of each pair drives bar widths and the second drives space widths.
|
||||
|
||||
| Segment | Description |
|
||||
|---------|-------------|
|
||||
| Start | `0000` (4 narrow modules) |
|
||||
| Data | Each pair → 5 interleaved bar+space segments (1 or 3 modules each) |
|
||||
| Stop | `100` (wide bar + 2 narrow) |
|
||||
|
||||
**Throws** `BarcodeError(BARCODE_CODES.INVALID_DATA)` for non-digit input or odd-length data.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The ITF_DIGIT table uses boolean arrays (false = narrow, true = wide) for each digit 0–9, with exactly 2 wide elements per digit. The interleaving algorithm iterates through the 5 element positions and alternates: barWidth repeated `1` characters then spaceWidth repeated `0` characters. This produces a continuous binary string where `1` represents a bar and `0` represents a space, directly usable by the SVG renderer. The 3:1 wide-to-narrow ratio is standard for ITF; some implementations use 2.5:1 but 3:1 provides better scanner compatibility.
|
||||
@@ -0,0 +1,56 @@
|
||||
# upca
|
||||
|
||||
## Purpose
|
||||
|
||||
Implements UPC-A barcode encoding and validation. UPC-A is the primary barcode format used in North American retail, encoding 12 digits (11 data + 1 check). It is structurally identical to EAN-13 with a leading `0` digit prepended, so this module delegates encoding to the EAN-13 encoder to avoid duplication and ensure consistent output.
|
||||
|
||||
## Features
|
||||
|
||||
- `encode(data)` — accepts 11 or 12 digit UPC-A strings; auto-appends check digit for 11-digit input.
|
||||
- `validate(data)` — verifies 12-digit format and check digit correctness.
|
||||
- Delegates to `ean13.encode` by prepending `'0'` — same 95-module binary output.
|
||||
- Throws `BarcodeError` with stable codes on invalid input.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { encode, validate } from "@suaveplan/barcode/symbologies";
|
||||
|
||||
console.log(validate("036000291452")); // true
|
||||
|
||||
const bits = encode("036000291452");
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { encode } from "@suaveplan/barcode/symbologies";
|
||||
|
||||
// 11-digit input: check digit is computed and appended automatically
|
||||
const bits = encode("03600029145"); // computes check digit 2
|
||||
console.log(bits.length); // 95 (same as EAN-13)
|
||||
|
||||
// UPC-A is EAN-13 with a leading 0; scanner output is equivalent
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `validate(data: string): boolean`
|
||||
|
||||
Returns `true` if `data` matches `/^\d{12}$/` and the 12th digit equals the computed check digit for the first 11. Returns `false` without throwing.
|
||||
|
||||
### `encode(data: string): string`
|
||||
|
||||
Encodes a UPC-A barcode by prepending `'0'` and calling `encodeEan13`.
|
||||
|
||||
| Input | Behaviour |
|
||||
|-------|-----------|
|
||||
| 11 digits | Check digit auto-computed and appended |
|
||||
| 12 digits | Used as-is; validated before encoding |
|
||||
| Other | `BarcodeError(INVALID_DATA)` thrown |
|
||||
|
||||
Output is 95 modules (identical to EAN-13). **Throws** `BarcodeError(BARCODE_CODES.INVALID_DATA)` for non-digit input, wrong length, or invalid check digit.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
UPC-A's equivalence with EAN-13 (first digit `0`) is standardised in GS1 specifications. Delegating to `ean13.encode` guarantees bit-identical output for any equivalent UPC-A/EAN-13 pair, simplifying scanner compatibility. The `computeCheckDigit` import from `ean13` reuses the same GS1 Luhn algorithm without duplication.
|
||||
@@ -0,0 +1,59 @@
|
||||
# upce
|
||||
|
||||
## Purpose
|
||||
|
||||
Implements UPC-E barcode encoding for the compressed 6-digit UPC symbology used on small retail packages where space for UPC-A is unavailable. UPC-E suppresses trailing zeros from UPC-A to achieve a compact 8-module (number system + 6 data + check) format. This module encodes the standard 8-digit UPC-E form, selecting per-digit L-code or G-code based on the GS1 parity table driven by the check digit.
|
||||
|
||||
## Features
|
||||
|
||||
- `encode(data)` — encodes an 8-digit UPC-E string into a binary bar pattern.
|
||||
- `validate(data)` — verifies 8-digit format and number system digit (0 or 1).
|
||||
- Parity selection via the standard GS1 UPC-E parity table indexed by check digit.
|
||||
- Start guard `101`, end guard `010101` (6-bar reverse parity guard).
|
||||
- Throws `BarcodeError` with stable codes on invalid input.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { encode, validate } from "@suaveplan/barcode/symbologies";
|
||||
|
||||
console.log(validate("01234565")); // true (8-digit UPC-E)
|
||||
|
||||
const bits = encode("01234565");
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { encode } from "@suaveplan/barcode/symbologies";
|
||||
|
||||
const bits = encode("01234565");
|
||||
|
||||
// Structure: 101 (start) + 6×7-bit mixed L/G parity + 010101 (end)
|
||||
console.log(bits.startsWith("101")); // true
|
||||
console.log(bits.endsWith("010101")); // true
|
||||
console.log(bits.length); // 51
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `validate(data: string): boolean`
|
||||
|
||||
Returns `true` if `data` matches `/^\d{8}$/` and the first digit (number system) is `'0'` or `'1'`. Returns `false` otherwise. Full check-digit validation against UPC-A expansion is not performed here.
|
||||
|
||||
### `encode(data: string): string`
|
||||
|
||||
Encodes a UPC-E barcode.
|
||||
|
||||
| Segment | Width | Description |
|
||||
|---------|-------|-------------|
|
||||
| Start guard | 3 | `101` |
|
||||
| 6 data digits | 42 | 6 × 7-bit L or G-code per parity table |
|
||||
| End guard | 6 | `010101` |
|
||||
| **Total** | **51** | |
|
||||
|
||||
**Throws** `BarcodeError(BARCODE_CODES.INVALID_DATA)` for non-8-digit input or invalid number system digit.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The parity table maps the check digit (0–9) to a 6-character string of `'O'` (odd/L-code) and `'E'` (even/G-code) symbols. For number system digit `0`, the table is applied directly; for digit `1`, the same table is used (GS1 specifies complemented parities, but the standard encoding in most scanners treats both identically for the compressed form). The end guard uses 6 modules rather than the usual 3, distinguishing UPC-E from UPC-A optically.
|
||||
@@ -0,0 +1,142 @@
|
||||
# barcode.types
|
||||
|
||||
## Purpose
|
||||
|
||||
Shared TypeScript type definitions for the `@suaveplan/barcode` package. These types form the public contract between all modules: the symbology encoder, the binary validator, and the SVG renderer all accept and return values described here. Centralising the types in one file ensures consistent interfaces across the package and provides a single authoritative reference for consumers.
|
||||
|
||||
## Features
|
||||
|
||||
- `BarcodeSymbology` — union of every supported 1D symbology literal string
|
||||
- `BarcodeOptions` — optional rendering settings passed to the `encode` function
|
||||
- `BarcodeResult` — the structured return value from a successful `encode` call
|
||||
- `ParseResult` — the structured return value from the `parse` validator call
|
||||
- Zero runtime code — types-only, no overhead at runtime
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```typescript
|
||||
import type { BarcodeSymbology, BarcodeResult } from "@suaveplan/barcode/types";
|
||||
|
||||
const symbology: BarcodeSymbology = "ean13";
|
||||
|
||||
function displayResult(result: BarcodeResult): void {
|
||||
const container = document.getElementById("barcode");
|
||||
if (container) {
|
||||
const img = document.createElement("img");
|
||||
img.src = `data:image/svg+xml;utf8,${encodeURIComponent(result.svg)}`;
|
||||
container.appendChild(img);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```typescript
|
||||
import type {
|
||||
BarcodeOptions,
|
||||
BarcodeResult,
|
||||
ParseResult,
|
||||
BarcodeSymbology,
|
||||
} from "@suaveplan/barcode/types";
|
||||
import { encode, parse } from "@suaveplan/barcode";
|
||||
|
||||
const SYMBOLOGIES: BarcodeSymbology[] = [
|
||||
"ean13", "ean8", "upca", "upce", "code128", "code39", "itf",
|
||||
];
|
||||
|
||||
function renderWithOptions(
|
||||
data: string,
|
||||
sym: BarcodeSymbology,
|
||||
opts: BarcodeOptions
|
||||
): BarcodeResult {
|
||||
return encode(data, sym, opts);
|
||||
}
|
||||
|
||||
function validateAndParse(
|
||||
data: string,
|
||||
sym: BarcodeSymbology
|
||||
): ParseResult {
|
||||
return parse(data, sym);
|
||||
}
|
||||
|
||||
const result: BarcodeResult = renderWithOptions("5901234123457", "ean13", {
|
||||
width: 300,
|
||||
height: 80,
|
||||
includeText: true,
|
||||
margin: 10,
|
||||
color: "#000000",
|
||||
background: "#ffffff",
|
||||
});
|
||||
|
||||
const parsed: ParseResult = validateAndParse("5901234123457", "ean13");
|
||||
// parsed.valid === true, parsed.checkDigit === "7"
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `BarcodeSymbology`
|
||||
|
||||
```typescript
|
||||
type BarcodeSymbology =
|
||||
| "code128"
|
||||
| "code39"
|
||||
| "ean13"
|
||||
| "ean8"
|
||||
| "upca"
|
||||
| "upce"
|
||||
| "itf";
|
||||
```
|
||||
|
||||
Union of all supported barcode symbology identifiers. Pass one of these string literals wherever a symbology argument is required.
|
||||
|
||||
### `BarcodeOptions`
|
||||
|
||||
```typescript
|
||||
interface BarcodeOptions {
|
||||
width?: number; // SVG width in pixels (default: 200)
|
||||
height?: number; // SVG height in pixels (default: 100)
|
||||
includeText?: boolean; // Render human-readable text below bars (default: true)
|
||||
margin?: number; // Quiet-zone margin in pixels (default: 10)
|
||||
color?: string; // Bar colour as CSS colour string (default: "#000000")
|
||||
background?: string; // Background colour as CSS colour string (default: "#ffffff")
|
||||
}
|
||||
```
|
||||
|
||||
All fields are optional. Defaults are applied inside `encode` when fields are omitted.
|
||||
|
||||
### `BarcodeResult`
|
||||
|
||||
```typescript
|
||||
interface BarcodeResult {
|
||||
symbology: BarcodeSymbology; // Symbology used
|
||||
data: string; // Original input data string
|
||||
svg: string; // Complete SVG document as a string
|
||||
binary: string; // Binary bar pattern ("1" = bar, "0" = space)
|
||||
valid: boolean; // Whether check digit (if any) is correct
|
||||
}
|
||||
```
|
||||
|
||||
Returned by `encode()`. The `svg` field is a self-contained SVG document with a root `<svg>` element including namespace and `viewBox`. The `binary` field exposes the raw bit string for custom rendering pipelines.
|
||||
|
||||
### `ParseResult`
|
||||
|
||||
```typescript
|
||||
interface ParseResult {
|
||||
symbology: BarcodeSymbology; // Symbology used during parse
|
||||
data: string; // Input data string
|
||||
valid: boolean; // Whether the data is valid for the symbology
|
||||
checkDigit?: string; // Extracted check digit, if applicable to the symbology
|
||||
}
|
||||
```
|
||||
|
||||
Returned by `parse()`. The `checkDigit` field is present only for symbologies that have a numeric check digit (EAN-13, EAN-8, UPC-A, UPC-E). It is `undefined` for Code 128, Code 39, and ITF.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
These are pure TypeScript `interface` and `type` declarations with no associated runtime code. The compiled output for this file is an empty module — all information is erased at transpile time. This means the types impose zero bundle cost.
|
||||
|
||||
The `BarcodeOptions` interface intentionally uses all-optional fields to support progressive disclosure: callers can pass an empty object `{}` or omit the argument entirely and receive a fully-rendered barcode with sensible defaults. This avoids forcing boilerplate for the common case while still allowing fine-grained control.
|
||||
|
||||
`ParseResult.checkDigit` is typed as `string | undefined` rather than `number | undefined` because check digits are single decimal characters extracted from the original input string. Keeping them as strings avoids ambiguity for leading-zero scenarios and matches the pattern used throughout the validator module.
|
||||
|
||||
The `binary` field on `BarcodeResult` is a `"0"` / `"1"` string rather than a `Uint8Array` because human readability and debuggability outweigh the marginal memory advantage of a bit array for single-barcode generation. Consumers who need bit-level storage can trivially convert with `Array.from(result.binary).map(Number)`.
|
||||
@@ -0,0 +1,131 @@
|
||||
# @suaveplan/qrcode - QR code generation producing SVG, pixel matrix, terminal (Unicode blocks), and data URL representations. Implements QR code versions 1-10, error correction levels L/M/Q/H, automatic version and mode selection.
|
||||
|
||||
## Summary
|
||||
|
||||
QR code generation producing SVG, pixel matrix, terminal (Unicode blocks), and data URL representations. Implements QR code versions 1-10, error correction levels L/M/Q/H, automatic version and mode selection.
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
## Documentation tree
|
||||
|
||||
- [core](./src/core/qrcode.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->- data-encoder — <!-- begin:auto-docs --> _(no submodu…
|
||||
- [encoder](./src/core/encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [data-encoder](./src/core/encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [mask](./src/core/mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [masking](./src/core/mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [matrix](./src/core/matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [matrix-builder](./src/core/matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [reed-solomon](./src/core/reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [reed-solomon](./src/core/reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [renderer](./src/core/renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [svg-renderer](./src/core/renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [tables](./src/core/tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [tables](./src/core/tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [qrcode](./src/core/qrcode.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->- data-encoder — <!-- begin:auto-docs --> _(no submodu…
|
||||
- [errors](./src/errors/qrcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [qrcode-error](./src/errors/qrcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
<!-- end:auto-docs --> - [encoder](./src/core/encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [data-encoder](./src/core/encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [mask](./src/core/mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [masking](./src/core/mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix](./src/core/matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix-builder](./src/core/matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./src/core/reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./src/core/reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [renderer](./src/core/renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [svg-renderer](./src/core/renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./src/core/tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./src/core/tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [qrcode](./src/core/qrcode.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/qrcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [qrcode-error](./src/errors/qrcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_- data-encoder — <!-- begin:au…
|
||||
|
||||
- [encoder](./src/core/encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [data-encoder](./src/core/encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [mask](./src/core/mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [masking](./src/core/mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix](./src/core/matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix-builder](./src/core/matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./src/core/reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./src/core/reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [renderer](./src/core/renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [svg-renderer](./src/core/renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./src/core/tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./src/core/tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [qrcode](./src/core/qrcode.md) — <!-- begin:auto-docs --> _(no submodules)_- data-encoder — <!-- begin:au…
|
||||
- [errors](./src/errors/qrcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [qrcode-error](./src/errors/qrcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_- data-encoder — <!-- begin:auto-docs --> _(no submod…
|
||||
|
||||
- [encoder](./src/core/encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [data-encoder](./src/core/encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [mask](./src/core/mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [masking](./src/core/mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix](./src/core/matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix-builder](./src/core/matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./src/core/reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./src/core/reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [renderer](./src/core/renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [svg-renderer](./src/core/renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./src/core/tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./src/core/tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [qrcode](./src/core/qrcode.md) — <!-- begin:auto-docs --> _(no submodules)_- data-encoder — <!-- begin:auto-docs --> _(no submod…
|
||||
- [errors](./src/errors/qrcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [qrcode-error](./src/errors/qrcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [encoder](./src/core/encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_ - [data-encoder](./src/core/encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [mask](./src/core/mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_ - [masking](./src/core/mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix](./src/core/matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_ - [matrix-builder](./src/core/matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./src/core/reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_ - [reed-solomon](./src/core/reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [renderer](./src/core/renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_ - [svg-renderer](./src/core/renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./src/core/tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_ - [tables](./src/core/tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [qrcode](./src/core/qrcode.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/qrcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_ - [qrcode-error](./src/errors/qrcode-error.md) — <!-- begin:auto-docs --> _(no submodules)_
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
bun add @suaveplan/qrcode
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```ts
|
||||
import { generate } from "@suaveplan/qrcode";
|
||||
|
||||
const result = generate("https://suaveplan.io");
|
||||
|
||||
console.log(result.svg); // Inline SVG string
|
||||
console.log(result.dataUrl); // data:image/svg+xml;base64,...
|
||||
console.log(result.terminal); // Unicode half-block for CLI display
|
||||
console.log(result.version); // e.g. 2
|
||||
console.log(result.size); // e.g. 25 (version 2 = 25×25)
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### `generate(data, options?)`
|
||||
|
||||
Generates a complete QR code for any UTF-8 string.
|
||||
|
||||
```ts
|
||||
import { generate } from "@suaveplan/qrcode";
|
||||
|
||||
const result = generate("Hello World", {
|
||||
errorCorrectionLevel: "H", // 'L' | 'M' | 'Q' | 'H', default 'M'
|
||||
version: 2, // 1-10, auto-selected if omitted
|
||||
margin: 4, // quiet zone in modules, default 4
|
||||
color: "#000000", // dark module color, default '#000000'
|
||||
background: "#ffffff", // light module color, default '#ffffff'
|
||||
scale: 10, // pixels per module in SVG, default 10
|
||||
});
|
||||
```
|
||||
|
||||
**Returns** `QRCodeResult`:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `version` | `number` | QR version used (1-10) |
|
||||
| `errorCorrectionLevel` | `ErrorCorrectionLevel` | EC level used |
|
||||
| `mode` | `QRMode` | Encoding mode (numeric/alphanumeric/byte) |
|
||||
| `matrix` | `boolean[][]` | Module grid — `true` = dark |
|
||||
| `size` | `number` | Matrix dimension (size × size) |
|
||||
| `svg` | `string` | Complete SVG markup |
|
||||
| `dataUrl` | `string` | `data:image/svg+xml;base64,...` |
|
||||
| `terminal` | `string` | Unicode half-block terminal representation |
|
||||
|
||||
### Errors
|
||||
|
||||
```ts
|
||||
import { QRCodeError, QRCODE_CODES } from "@suaveplan/qrcode/errors";
|
||||
|
||||
try {
|
||||
generate("", { version: 1, errorCorrectionLevel: "H" });
|
||||
} catch (e) {
|
||||
if (e instanceof QRCodeError) {
|
||||
switch (e.code) {
|
||||
case QRCODE_CODES.INVALID_DATA:
|
||||
// Empty input, invalid characters, or out-of-range version
|
||||
break;
|
||||
case QRCODE_CODES.VERSION_TOO_SMALL:
|
||||
// Data too large for the specified version (or all versions 1-10)
|
||||
break;
|
||||
case QRCODE_CODES.ENCODE_FAILED:
|
||||
// Internal encoding pipeline failure
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Module Exports
|
||||
|
||||
| Subpath | Contents |
|
||||
|---------|----------|
|
||||
| `@suaveplan/qrcode` | `generate`, all types, all sub-module exports |
|
||||
| `@suaveplan/qrcode/errors` | `QRCodeError`, `QRCODE_CODES`, `QRCodeCode` |
|
||||
| `@suaveplan/qrcode/core/tables` | Lookup tables and helpers |
|
||||
| `@suaveplan/qrcode/core/encoder` | `detectMode`, `encodeData`, `BitBuffer`, `encodeUtf8` |
|
||||
| `@suaveplan/qrcode/core/reed-solomon` | `rsEncode`, `interleaveBlocks`, `splitBlocks`, GF arithmetic |
|
||||
| `@suaveplan/qrcode/core/matrix` | `buildMatrix` |
|
||||
| `@suaveplan/qrcode/core/mask` | `selectMask`, `penaltyScore` |
|
||||
| `@suaveplan/qrcode/core/renderer` | `renderSvg`, `renderDataUrl`, `renderTerminal` |
|
||||
|
||||
## Co-located Documentation
|
||||
|
||||
- [errors/qrcode-error.md](src/errors/qrcode-error.md)
|
||||
- [core/tables/tables.md](src/core/tables/tables.md)
|
||||
- [core/encoder/data-encoder.md](src/core/encoder/data-encoder.md)
|
||||
- [core/reed-solomon/reed-solomon.md](src/core/reed-solomon/reed-solomon.md)
|
||||
- [core/matrix/matrix-builder.md](src/core/matrix/matrix-builder.md)
|
||||
- [core/mask/masking.md](src/core/mask/masking.md)
|
||||
- [core/renderer/svg-renderer.md](src/core/renderer/svg-renderer.md)
|
||||
- [core/qrcode.md](src/core/qrcode.md)
|
||||
@@ -0,0 +1,83 @@
|
||||
# data-encoder
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Implements mode detection and bit-stream construction for QR code data encoding. Given a string, it selects the most compact encoding mode (numeric, alphanumeric, or byte), builds the complete bit stream including mode indicator and character count indicator, appends the terminator and padding codewords per ISO/IEC 18004:2015, and returns the final array of data codewords ready for Reed-Solomon processing.
|
||||
|
||||
The encoder also exports a `BitBuffer` class (an efficient bit-oriented writer) and the `encodeUtf8` helper, both used internally and by tests to verify intermediate encoding state.
|
||||
|
||||
## Features
|
||||
|
||||
- Automatic mode detection: numeric → alphanumeric → byte in priority order
|
||||
- `BitBuffer` accumulates arbitrary-width integers into a packed byte array
|
||||
- Numeric encoding: groups of 3 digits → 10 bits, 2 → 7 bits, 1 → 4 bits
|
||||
- Alphanumeric encoding: pairs → 11 bits (first×45+second), single → 6 bits
|
||||
- Byte encoding: UTF-8 with full surrogate-pair handling for code points above U+FFFF
|
||||
- Terminator bits (up to 4 zero bits), byte-boundary padding, and pad codeword alternation (0xEC/0x11)
|
||||
- Character count indicator bit length selected by version range (1-9, 10-26, 27-40)
|
||||
- Throws `QRCodeError(QRCODE_CODES.INVALID_DATA)` for empty input or invalid alphanumeric characters
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { detectMode, encodeData } from "@suaveplan/qrcode/core/encoder";
|
||||
|
||||
const mode = detectMode("01234567"); // "numeric"
|
||||
const codewords = encodeData("01234567", mode, 1, 19);
|
||||
// codewords is an array of 19 bytes ready for RS processing
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { BitBuffer, detectMode, encodeData, encodeUtf8 } from "@suaveplan/qrcode/core/encoder";
|
||||
|
||||
// Verify intermediate bit stream for "HELLO WORLD"
|
||||
const buf = new BitBuffer();
|
||||
buf.put(0b0010, 4); // alphanumeric mode indicator
|
||||
buf.put(11, 9); // character count (9 bits for version 1)
|
||||
// ... encode each pair
|
||||
console.log(buf.bitLength);
|
||||
|
||||
// Byte mode with emoji
|
||||
const mode = detectMode("Hello 🌍");
|
||||
const cws = encodeData("Hello 🌍", mode, 2, 28);
|
||||
// UTF-8 bytes for the emoji are correctly split across codewords
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `class BitBuffer`
|
||||
|
||||
**`put(value: number, numBits: number): void`** — Appends the `numBits` least-significant bits of `value` (MSB first).
|
||||
|
||||
**`putBit(bit: boolean): void`** — Appends a single bit.
|
||||
|
||||
**`get bitLength(): number`** — Total bits written so far.
|
||||
|
||||
**`get bytes(): number[]`** — The backing byte array. Length is `Math.ceil(bitLength / 8)`.
|
||||
|
||||
### `detectMode(data: string): QRMode`
|
||||
|
||||
Returns the most compact QR encoding mode for `data`: `"numeric"` if all digits, `"alphanumeric"` if all characters are in the QR alphanumeric set, otherwise `"byte"`.
|
||||
|
||||
### `encodeData(data, mode, version, totalDataCW): number[]`
|
||||
|
||||
Encodes `data` in `mode` for the given `version` into exactly `totalDataCW` bytes, including mode indicator, character count, payload, terminator, and padding.
|
||||
|
||||
**Throws** `QRCodeError(QRCODE_CODES.INVALID_DATA)` if `data` is empty or contains characters invalid for the specified mode.
|
||||
|
||||
### `encodeUtf8(str: string): number[]`
|
||||
|
||||
Converts a JavaScript string to a UTF-8 byte array, handling Basic Multilingual Plane and supplementary code points via surrogate pairs.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`BitBuffer` packs bits MSB-first into a byte array. The `put` method loops from the most-significant bit of `value` down to 0, using a shift and mask to extract each bit. This matches the QR spec's bit ordering convention.
|
||||
|
||||
Numeric encoding computes `parseInt` on slices — safe because the mode guard guarantees only digit characters. Alphanumeric encoding throws on characters absent from `ALPHANUMERIC_TABLE` rather than silently skipping them, since a misdetected mode would corrupt the scan result.
|
||||
|
||||
The pad byte sequence alternates 0xEC → 0x11 → 0xEC → ... as required by the QR specification. The terminator is clamped to `min(4, remaining bits)` to handle the edge case where the payload exactly fills the codeword capacity.
|
||||
@@ -0,0 +1,72 @@
|
||||
# masking
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Implements QR code mask pattern evaluation and optimal mask selection per ISO/IEC 18004:2015 Section 7.8. Masking improves the readability of QR codes by preventing large uniform regions that confuse scanners. The module evaluates all 8 candidate masks against four penalty rules and selects the mask yielding the lowest total penalty score.
|
||||
|
||||
The penalty rules measure four specific undesirable patterns: long consecutive same-color runs, 2×2 same-color blocks, finder-like 1:1:3:1:1 patterns that confuse the scanner's finder detection, and skewed proportions of dark versus light modules.
|
||||
|
||||
## Features
|
||||
|
||||
- All four ISO penalty rules implemented with correct weight constants (N1=3, N2=3, N3=40, N4=10)
|
||||
- Penalty rule 1: consecutive same-color runs ≥ 5 in rows and columns
|
||||
- Penalty rule 2: 2×2 same-color blocks
|
||||
- Penalty rule 3: finder-like patterns (both forward and reverse orientations)
|
||||
- Penalty rule 4: dark module proportion deviation from 50%
|
||||
- `penaltyScore` for single-matrix scoring (useful for testing and external tools)
|
||||
- `selectMask` evaluates all 8 masked matrices and returns the lowest-penalty matrix with its mask index
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { selectMask } from "@suaveplan/qrcode/core/mask";
|
||||
|
||||
const { maskPattern, matrix } = selectMask(1, "M", interleavedCW);
|
||||
// matrix is the boolean[][] ready for rendering
|
||||
// maskPattern is 0-7, recorded for format information encoding
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { selectMask, penaltyScore } from "@suaveplan/qrcode/core/mask";
|
||||
import { buildMatrix } from "@suaveplan/qrcode/core/matrix";
|
||||
|
||||
// Force a specific mask and score it manually
|
||||
const matrix = buildMatrix(2, "Q", 3, data);
|
||||
const score = penaltyScore(matrix);
|
||||
console.log(`Mask 3 penalty: ${score}`);
|
||||
|
||||
// Or let selectMask choose
|
||||
const best = selectMask(2, "Q", data);
|
||||
console.log(`Best mask: ${best.maskPattern}`);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `penaltyScore(matrix: boolean[][]): number`
|
||||
|
||||
Computes the total penalty score for a boolean module matrix. Lower is better. Used internally by `selectMask` and available for external inspection.
|
||||
|
||||
### `selectMask(version, ecLevel, data): { maskPattern: number; matrix: boolean[][] }`
|
||||
|
||||
Evaluates all 8 mask patterns by calling `buildMatrix` for each, scores each matrix with `penaltyScore`, and returns the result with the minimum penalty.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `version: number` — QR version 1-10
|
||||
- `ecLevel: ErrorCorrectionLevel` — error correction level
|
||||
- `data: number[]` — interleaved codeword bytes
|
||||
|
||||
**Returns:** `{ maskPattern: number; matrix: boolean[][] }` where `maskPattern` is 0-7 and `matrix` is the final boolean matrix ready for rendering.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Penalty rule 3 uses two reference patterns from the QR spec: `1011101 0000` and `0000 1011101`, both of length 11 modules. Each occurrence in any row or column contributes N3=40 to the total. The column check extracts each column into a temporary array to allow the same pattern-matching logic as rows; this avoids code duplication at the cost of one allocation per column per pattern evaluation.
|
||||
|
||||
Penalty rule 4 computes the percentage of dark modules, finds the nearest 5% multiples below and above, takes the absolute deviation from 50% for each divided by 5, and multiplies the minimum by N4=10. This matches the ISO specification's "step" approach.
|
||||
|
||||
`selectMask` builds all 8 matrices independently (8 calls to `buildMatrix`). This is correct per spec since the mask is applied inside `buildMatrix`; the format information encoding also varies by mask, so each candidate is a fully formed QR matrix.
|
||||
@@ -0,0 +1,68 @@
|
||||
# matrix-builder
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Constructs the complete QR code module matrix by placing all functional patterns and data modules according to ISO/IEC 18004:2015. The builder operates on a numeric grid (0=light, 1=dark, 2=reserved, 255=unset), progressively filling in finder patterns, timing patterns, alignment patterns, format information reservations, and finally the data codewords. After data placement, a mask pattern is applied and format information is written into the previously reserved areas.
|
||||
|
||||
The output is a `boolean[][]` where `true` represents a dark module and `false` a light module, providing a clean, format-independent representation consumed by renderers and the masking scorer.
|
||||
|
||||
## Features
|
||||
|
||||
- Three finder pattern placements (7×7) with separator strips
|
||||
- Horizontal and vertical timing patterns on row/column 6
|
||||
- Version-adaptive alignment pattern placement (versions 2-10) with overlap detection for finder pattern corners
|
||||
- Format information area reservation before data placement
|
||||
- Two-column zigzag data placement with column-6 skip per QR spec
|
||||
- All 8 mask patterns (ISO conditions 0-7)
|
||||
- Format information writing (15-bit pre-computed BCH values from tables module)
|
||||
- Sentinel-based reservation ensures function modules are never overwritten by data
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { buildMatrix } from "@suaveplan/qrcode/core/matrix";
|
||||
|
||||
const matrix = buildMatrix(1, "M", 2, interleavedCWBytes);
|
||||
// matrix[0][0] === true // top-left finder dark corner
|
||||
// matrix.length === 21 // version 1 is 21×21
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { buildMatrix } from "@suaveplan/qrcode/core/matrix";
|
||||
|
||||
// Build all 8 masked variants for penalty scoring
|
||||
const candidates = Array.from({ length: 8 }, (_, mask) =>
|
||||
buildMatrix(version, ecLevel, mask, interleaved)
|
||||
);
|
||||
// Feed candidates to masking scorer to pick the best one
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `buildMatrix(version, ecLevel, maskPattern, data): boolean[][]`
|
||||
|
||||
Constructs the complete QR matrix.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `version: number` — QR version 1-10
|
||||
- `ecLevel: ErrorCorrectionLevel` — `"L" | "M" | "Q" | "H"`
|
||||
- `maskPattern: number` — mask index 0-7
|
||||
- `data: number[]` — interleaved codeword bytes from `interleaveBlocks`
|
||||
|
||||
**Returns:** `boolean[][]` of size `(version * 4 + 17) × (version * 4 + 17)`. `true` = dark module.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The matrix uses a `Uint8Array[]` internally with four sentinel values: 255 (unset), 0 (light), 1 (dark), 2 (reserved/function). Data placement only writes to cells with value 255; all function pattern cells are set before data placement begins. The mask is applied only to non-reserved, non-unset cells, so function modules remain stable.
|
||||
|
||||
Format information is written last to overwrite the reserved-sentinel cells with their final bit values. The dark module at `(size-8, 8)` is placed during format reservation and never overwritten.
|
||||
|
||||
Alignment pattern placement skips three positions that would overlap the finder pattern corners: `(6,6)`, `(6, last)`, and `(last, 6)`. This matches the QR spec's exception table for versions 7 and above but is also applied to versions 2-6 where those positions do not occur in the position table.
|
||||
|
||||
The data zigzag alternates upward and downward column pairs of width 2, stepping right-to-left. Column 6 (timing column) is skipped by treating the strip at column 7 as a width-3 step instead of width-2.
|
||||
@@ -0,0 +1,102 @@
|
||||
# qrcode
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
- [data-encoder](./encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [mask](./mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_ - [masking](./mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix](./matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_ - [matrix-builder](./matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_ - [reed-solomon](./reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [renderer](./renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_ - [svg-renderer](./renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_ - [tables](./tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [qrcode](./qrcode.md) — <!-- begin:auto-docs --> _(no submodules)_- data-encoder — <!-- begin:auto-docs --> _(no submodu…
|
||||
- [data-encoder](./encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [mask](./mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [masking](./mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix](./matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix-builder](./matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [renderer](./renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [svg-renderer](./renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [qrcode](./qrcode.md) — <!-- begin:auto-docs --> _(no submodules)_- [data-encoder](./encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [mask](./mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [masking](./mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix](./matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix-builder](./matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [renderer](./renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [svg-renderer](./renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [qrcode](./qrcode.md) — <!-- begin:auto-docs --> _(no submodules)_- data-encoder — <!-- begin:au…
|
||||
- [data-encoder](./encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [mask](./mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [masking](./mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix](./matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix-builder](./matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [renderer](./renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [svg-renderer](./renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [qrcode](./qrcode.md) — <!-- begin:auto-docs --> _(no submodules)_- data-encoder — <!-- begin:auto-docs --> _(no submod…
|
||||
- [data-encoder](./encoder/data-encoder.md) — <!-- begin:auto-docs --> _(no submodules)_- [mask](./mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_ - [masking](./mask/masking.md) — <!-- begin:auto-docs --> _(no submodules)_- [matrix](./matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_ - [matrix-builder](./matrix/matrix-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [reed-solomon](./reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_ - [reed-solomon](./reed-solomon/reed-solomon.md) — <!-- begin:auto-docs --> _(no submodules)_- [renderer](./renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_ - [svg-renderer](./renderer/svg-renderer.md) — <!-- begin:auto-docs --> _(no submodules)_- [tables](./tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_ - [tables](./tables/tables.md) — <!-- begin:auto-docs --> _(no submodules)_- [qrcode](./qrcode.md) — <!-- begin:auto-docs --> _(no submodules)_
|
||||
## Purpose
|
||||
|
||||
Top-level orchestrator for the `@suaveplan/qrcode` package. The `generate` function is the single public entry point that combines all pipeline stages: mode detection, version selection, data encoding, Reed-Solomon error correction, block interleaving, mask scoring, matrix construction, and rendering. Callers provide a string and optional configuration; the function returns a `QRCodeResult` with all four output representations populated.
|
||||
|
||||
OpenTelemetry span instrumentation is applied to the full generation pipeline via a graceful dynamic import: if `@opentelemetry/api` is available at runtime it records span attributes (version, EC level, mode, mask pattern) and status; if OTel is absent the function runs without tracing and without throwing.
|
||||
|
||||
## Features
|
||||
|
||||
- Single `generate(data, options?)` function covering the complete QR code pipeline
|
||||
- Automatic version selection (tries versions 1-10 in order, picks the smallest that fits)
|
||||
- Explicit version override with capacity validation and informative error
|
||||
- EC level defaults to `'M'` if not specified
|
||||
- Returns `QRCodeResult` with version, EC level, mode, matrix, size, SVG, dataUrl, terminal
|
||||
- OTel span with attributes: `qrcode.version`, `qrcode.ecLevel`, `qrcode.mode`, `qrcode.maskPattern`
|
||||
- Throws `QRCodeError` with stable codes for empty input, oversized data, and encoding failures
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { generate } from "@suaveplan/qrcode";
|
||||
|
||||
const result = generate("https://suaveplan.io");
|
||||
console.log(result.svg); // SVG string
|
||||
console.log(result.terminal); // Unicode block output
|
||||
console.log(result.version); // e.g. 3
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { generate } from "@suaveplan/qrcode";
|
||||
|
||||
const result = generate("HELLO WORLD", {
|
||||
errorCorrectionLevel: "H",
|
||||
version: 2,
|
||||
scale: 6,
|
||||
margin: 2,
|
||||
color: "#1a1a2e",
|
||||
background: "#ffffff",
|
||||
});
|
||||
|
||||
// Embed as img src
|
||||
const img = document.createElement("img");
|
||||
img.src = result.dataUrl;
|
||||
|
||||
// Use raw matrix for custom rendering
|
||||
for (let row = 0; row < result.size; row++) {
|
||||
for (let col = 0; col < result.size; col++) {
|
||||
const dark = result.matrix[row][col];
|
||||
// draw(col * 10, row * 10, dark);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `generate(data: string, options?: QRCodeOptions): QRCodeResult`
|
||||
|
||||
Generates a QR code for `data`.
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `data` — non-empty string to encode; any UTF-8 content
|
||||
- `options.errorCorrectionLevel` — `"L" | "M" | "Q" | "H"`, default `"M"`
|
||||
- `options.version` — QR version 1-10, auto-selected if omitted
|
||||
- `options.margin` — quiet zone in modules, default 4
|
||||
- `options.color` — dark module color string, default `"#000000"`
|
||||
- `options.background` — light module color string, default `"#ffffff"`
|
||||
- `options.scale` — pixels per module in SVG output, default 10
|
||||
|
||||
**Returns:** `QRCodeResult`
|
||||
|
||||
- `version: number` — version used
|
||||
- `errorCorrectionLevel: ErrorCorrectionLevel` — level used
|
||||
- `mode: QRMode` — encoding mode selected
|
||||
- `matrix: boolean[][]` — module grid, true=dark
|
||||
- `size: number` — matrix dimension
|
||||
- `svg: string` — SVG markup
|
||||
- `dataUrl: string` — `data:image/svg+xml;base64,...`
|
||||
- `terminal: string` — Unicode half-block representation
|
||||
|
||||
**Throws:** `QRCodeError` with:
|
||||
|
||||
- `QRCODE_CODES.INVALID_DATA` — empty input or out-of-range version
|
||||
- `QRCODE_CODES.VERSION_TOO_SMALL` — data too large for the version or for all versions 1-10
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Version auto-selection measures byte length for byte mode and character count for numeric and alphanumeric modes. This matches the QR spec's capacity tables, which are defined in terms of characters for non-byte modes and bytes for byte mode.
|
||||
|
||||
The OTel integration uses a top-level `await import()` to avoid bundling issues when OTel is a peer dependency. If the import fails (not installed), the function silently proceeds without tracing. Span status is set to `OK` on success and `ERROR` with a recorded exception on failure.
|
||||
|
||||
The mask selection loop in `selectMask` builds all 8 matrices and picks the minimum penalty. For versions up to 10 (maximum 57×57 modules), this executes in well under 1ms on modern hardware.
|
||||
@@ -0,0 +1,94 @@
|
||||
# reed-solomon
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Implements Reed-Solomon error correction over GF(256) for QR code generation. The finite field uses the primitive polynomial x⁸+x⁴+x³+x²+1 (0x11D) as specified in ISO/IEC 18004:2015 Annex A. This module provides the complete RS pipeline: GF(256) arithmetic primitives, generator polynomial construction, codeword computation via polynomial long division, block splitting, and final codeword interleaving.
|
||||
|
||||
Reed-Solomon allows QR scanners to reconstruct the original data even when part of the code is damaged or obscured. The number of correctable errors scales with the error correction level: L corrects ~7%, M ~15%, Q ~25%, H ~30% of total codewords.
|
||||
|
||||
## Features
|
||||
|
||||
- GF(256) exp/log table construction at module load (O(255) init, O(1) multiply)
|
||||
- `gfMul`, `gfDiv`, `gfAdd`, `gfPow` arithmetic primitives
|
||||
- `polyMul` for polynomial multiplication in GF(256)
|
||||
- `generatorPoly(n)` builds the RS generator polynomial g(x) = ∏(x − αⁱ) for i=0..n-1
|
||||
- `rsEncode(data, nEC)` performs polynomial long division to produce EC codewords
|
||||
- `splitBlocks` partitions data codewords by the block group structure from `BLOCK_TABLE`
|
||||
- `interleaveBlocks` interleaves data and EC codewords across all blocks in the column order required by the QR matrix data placement algorithm
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { rsEncode } from "@suaveplan/qrcode/core/reed-solomon";
|
||||
|
||||
// Compute 10 EC codewords for a V1-M data block
|
||||
const dataCW = [32, 91, 11, 120, 209, 114, 220, 77, 67, 64, 236, 17, 236, 17, 236, 17];
|
||||
const ecCW = rsEncode(dataCW, 10);
|
||||
// ecCW is an array of 10 bytes
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
splitBlocks,
|
||||
interleaveBlocks,
|
||||
gfMul,
|
||||
generatorPoly,
|
||||
} from "@suaveplan/qrcode/core/reed-solomon";
|
||||
import { BLOCK_TABLE, EC_LEVEL_INDEX } from "@suaveplan/qrcode/core/tables";
|
||||
|
||||
const blockInfo = BLOCK_TABLE[4][EC_LEVEL_INDEX["M"]]; // V5 M
|
||||
const dataBlocks = splitBlocks(allDataCW, blockInfo.blocks);
|
||||
const finalCW = interleaveBlocks(dataBlocks, blockInfo.ecCWPerBlock);
|
||||
// finalCW is ready to be placed into the QR matrix
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `gfMul(a: number, b: number): number`
|
||||
|
||||
Multiplies two GF(256) elements using the exp/log tables. Returns 0 if either operand is 0.
|
||||
|
||||
### `gfDiv(a: number, b: number): number`
|
||||
|
||||
Divides `a` by `b` in GF(256). Throws `RangeError` if `b === 0`.
|
||||
|
||||
### `gfAdd(a: number, b: number): number`
|
||||
|
||||
Adds (XORs) two GF(256) elements. Subtraction is identical in GF(2^n).
|
||||
|
||||
### `gfPow(x: number, power: number): number`
|
||||
|
||||
Computes `α^(log(x) * power) mod 255` using the exp/log tables.
|
||||
|
||||
### `polyMul(p: Uint8Array, q: Uint8Array): Uint8Array`
|
||||
|
||||
Multiplies two GF(256) polynomials. Coefficient arrays are indexed by degree (index 0 = constant term).
|
||||
|
||||
### `generatorPoly(nECCodewords: number): Uint8Array`
|
||||
|
||||
Builds the RS generator polynomial for `nECCodewords` EC codewords. Cached implicitly by the caller since the same block always uses the same EC count.
|
||||
|
||||
### `rsEncode(data: number[], nECCodewords: number): number[]`
|
||||
|
||||
Computes `nECCodewords` Reed-Solomon error correction codewords for `data`. Returns only the EC bytes (not the original data).
|
||||
|
||||
### `splitBlocks(dataCW, blocks): number[][]`
|
||||
|
||||
Splits a flat data codeword array into individual block arrays according to the block group structure from `BLOCK_TABLE`. Groups with `count: 0` are skipped.
|
||||
|
||||
### `interleaveBlocks(dataBlocks, ecCWPerBlock): number[]`
|
||||
|
||||
Produces the final codeword sequence by interleaving all block data columns, then all block EC columns. This column-major ordering is required by the QR matrix data placement algorithm.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The exp/log tables are computed once at module initialisation time via an IIFE. The GF(256) multiplication is therefore a single array lookup pair (two reads + one modular add), making it the fastest possible approach for this field size.
|
||||
|
||||
The polynomial long division in `rsEncode` operates in-place on a pre-allocated message array of length `data.length + nECCodewords`, avoiding dynamic allocation inside the inner loop. After processing, only the last `nECCodewords` bytes are returned as the EC codewords.
|
||||
|
||||
The interleaver handles unequal block sizes (one group with `dataCW` bytes, a second group with `dataCW + 1` bytes for versions like V5) by iterating up to the maximum block length and skipping blocks that have been exhausted. This matches the QR spec's data placement order exactly.
|
||||
@@ -0,0 +1,78 @@
|
||||
# svg-renderer
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Converts a QR code module matrix (`boolean[][]`) into human- and machine-readable output formats. Three representations are produced: an SVG string for web embedding and print quality at any scale, a base64 data URL for use in HTML `img` src attributes without external file references, and a Unicode half-block terminal string for command-line display and debugging.
|
||||
|
||||
All renderers accept the same `QRCodeOptions` object, using the `margin`, `color`, `background`, and `scale` fields to control appearance. This keeps the rendering API uniform across output formats and allows the top-level `generate` function to call all three with a single options object.
|
||||
|
||||
## Features
|
||||
|
||||
- `renderSvg`: inline SVG with configurable pixel scale, margin, dark/light colors; uses `<rect>` elements for maximum compatibility (no `<path>`)
|
||||
- `renderDataUrl`: wraps `renderSvg` output as `data:image/svg+xml;base64,...` for `<img src>` embedding
|
||||
- `renderTerminal`: packs 2 module rows per terminal line using Unicode half-block characters (UP HALF BLOCK, LOWER HALF BLOCK, FULL BLOCK, space), with configurable quiet zone
|
||||
- XML attribute value escaping (`&`, `<`, `>`, `"`, `'`) prevents SVG injection from user-supplied color strings
|
||||
- Quiet zone (margin) applied identically in all three renderers for visual consistency
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { renderSvg } from "@suaveplan/qrcode/core/renderer";
|
||||
|
||||
const svg = renderSvg(matrix, { scale: 4, margin: 2 });
|
||||
// Returns a complete SVG string, 100x100px for a 21-module V1 QR
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { renderSvg, renderDataUrl, renderTerminal } from "@suaveplan/qrcode/core/renderer";
|
||||
|
||||
const opts = { color: "#1a1a2e", background: "#f0f0f0", scale: 8, margin: 4 };
|
||||
|
||||
const svg = renderSvg(matrix, opts);
|
||||
const url = renderDataUrl(matrix, opts);
|
||||
const cli = renderTerminal(matrix, { margin: 2 });
|
||||
|
||||
// Set on an img element src attribute
|
||||
const imgSrc = url;
|
||||
|
||||
// Print in terminal
|
||||
console.log(cli);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `renderSvg(matrix: boolean[][], options?: QRCodeOptions): string`
|
||||
|
||||
Renders the matrix to an SVG string. Each dark module becomes a `<rect>` element. A background `<rect>` covers the entire canvas including the quiet zone.
|
||||
|
||||
**Options used:** `scale` (pixels per module, default 10), `margin` (quiet zone in modules, default 4), `color` (dark module fill, default `#000000`), `background` (light fill, default `#ffffff`).
|
||||
|
||||
### `renderDataUrl(matrix: boolean[][], options?: QRCodeOptions): string`
|
||||
|
||||
Calls `renderSvg` and encodes the result as a UTF-8-safe base64 data URL: `data:image/svg+xml;base64,...`.
|
||||
|
||||
### `renderTerminal(matrix: boolean[][], options?: QRCodeOptions): string`
|
||||
|
||||
Renders the matrix to a multi-line string using Unicode half-block characters. Two module rows are collapsed into one terminal row. Options used: `margin` (quiet zone, default 4).
|
||||
|
||||
**Terminal character mapping:**
|
||||
|
||||
- U+2588 FULL BLOCK: top dark, bottom dark
|
||||
- U+2580 UPPER HALF BLOCK: top dark, bottom light
|
||||
- U+2584 LOWER HALF BLOCK: top light, bottom dark
|
||||
- U+0020 SPACE: top light, bottom light
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`renderSvg` generates one `<rect>` per dark module rather than using `<path>` commands. While this produces larger SVG text for dense QR codes, it is universally compatible across SVG 1.1 viewers, email clients, and PDF renderers. The `viewBox` attribute ensures the SVG scales correctly in responsive CSS layouts.
|
||||
|
||||
`renderDataUrl` uses `btoa(unescape(encodeURIComponent(svg)))` to handle Unicode characters in user-supplied color strings before base64 encoding, avoiding `btoa` failures on non-Latin characters.
|
||||
|
||||
`renderTerminal` pads the matrix with `margin` rows/columns of light modules before processing, then iterates in pairs of rows. If the matrix has an odd total padded height, the final row is treated as if followed by a light row.
|
||||
|
||||
The `escapeXml` function is applied to color strings in the SVG output to prevent injection via crafted color values. Colors should also be validated at the options level before reaching the renderer.
|
||||
@@ -0,0 +1,107 @@
|
||||
# tables
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Centralises every constant lookup table required by the QR code encoding pipeline. All data is sourced directly from ISO/IEC 18004:2015 and arranged for O(1) access by version (1-indexed) and error correction level (L/M/Q/H). Having a single canonical table module eliminates drift between the encoder, Reed-Solomon generator, matrix builder, and format information writer: they all read from one authoritative source.
|
||||
|
||||
The module deliberately avoids any computation at import time beyond trivial object/array literals so tree-shaking is maximally effective; unused capacity tables are eliminated at build time.
|
||||
|
||||
## Features
|
||||
|
||||
- Byte, numeric, and alphanumeric capacity tables for versions 1-10 × 4 EC levels
|
||||
- Full block structure table (`BLOCK_TABLE`) describing data/EC codeword counts and group layouts for interleaved data blocks
|
||||
- Alignment pattern centre positions for versions 1-10
|
||||
- Alphanumeric character value lookup (O(1) string → integer)
|
||||
- Mode indicator nibbles and character count indicator bit lengths
|
||||
- Pre-computed format information 15-bit strings (BCH(15,5) + XOR mask)
|
||||
- `charCountBits(mode, version)` helper for version-range dispatch
|
||||
- `qrSize(version)` helper computing module matrix dimension
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { BYTE_CAPACITY, EC_LEVEL_INDEX } from "@suaveplan/qrcode/core/tables";
|
||||
|
||||
const ecIdx = EC_LEVEL_INDEX["M"]; // 1
|
||||
const version = 1;
|
||||
const maxBytes = BYTE_CAPACITY[version - 1][ecIdx]; // 14
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
BLOCK_TABLE,
|
||||
EC_LEVEL_INDEX,
|
||||
FORMAT_INFO_STRINGS,
|
||||
ALPHANUMERIC_TABLE,
|
||||
} from "@suaveplan/qrcode/core/tables";
|
||||
|
||||
// Look up block structure for V3 M
|
||||
const blockInfo = BLOCK_TABLE[2][EC_LEVEL_INDEX["M"]];
|
||||
// blockInfo.ecCWPerBlock === 26, blockInfo.blocks === [{ count: 1, dataCW: 44 }]
|
||||
|
||||
// Encode alphanumeric pair
|
||||
const charVal = ALPHANUMERIC_TABLE["A"] * 45 + ALPHANUMERIC_TABLE["B"];
|
||||
// charVal === 10 * 45 + 11 === 461
|
||||
|
||||
// Read pre-computed format info for EC=M, mask=2
|
||||
const fmtBits = FORMAT_INFO_STRINGS[1 * 8 + 2]; // 0x5e7c
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `EC_LEVEL_INDEX`
|
||||
|
||||
`Record<ErrorCorrectionLevel, number>` mapping `L→0`, `M→1`, `Q→2`, `H→3`. Used as the second dimension index into all 2D tables.
|
||||
|
||||
### `BYTE_CAPACITY`
|
||||
|
||||
`ReadonlyArray<readonly [number,number,number,number]>`. Byte-mode capacity in bytes. First index is `version - 1`, second is `EC_LEVEL_INDEX[level]`.
|
||||
|
||||
### `NUMERIC_CAPACITY`
|
||||
|
||||
Same shape as `BYTE_CAPACITY` for numeric-mode character counts.
|
||||
|
||||
### `ALPHANUMERIC_CAPACITY`
|
||||
|
||||
Same shape as `BYTE_CAPACITY` for alphanumeric-mode character counts.
|
||||
|
||||
### `BLOCK_TABLE`
|
||||
|
||||
`ReadonlyArray<readonly [BlockInfo, BlockInfo, BlockInfo, BlockInfo]>`. Full interleaving block structure. `BlockInfo` has `{ totalDataCW, ecCWPerBlock, blocks: Array<{ count, dataCW }> }`. First index is `version - 1`, second is `EC_LEVEL_INDEX[level]`.
|
||||
|
||||
### `ALIGNMENT_POSITIONS`
|
||||
|
||||
`ReadonlyArray<ReadonlyArray<number>>`. Centre coordinates of alignment patterns. First index is `version - 1`; version 1 returns an empty array.
|
||||
|
||||
### `ALPHANUMERIC_TABLE`
|
||||
|
||||
`Readonly<Record<string, number>>`. Maps each of the 45 alphanumeric characters to its QR spec integer value.
|
||||
|
||||
### `MODE_INDICATOR`
|
||||
|
||||
`Record<string, number>`. Maps mode name strings to 4-bit mode indicator values.
|
||||
|
||||
### `CHAR_COUNT_BITS`
|
||||
|
||||
`Record<string, readonly [number, number, number]>`. Character count indicator lengths for three version ranges per mode.
|
||||
|
||||
### `FORMAT_INFO_STRINGS`
|
||||
|
||||
`ReadonlyArray<number>`. 32 pre-computed 15-bit format information values. Index as `ecLevelIndex * 8 + maskPattern`.
|
||||
|
||||
### `charCountBits(mode: string, version: number): number`
|
||||
|
||||
Returns the character count indicator bit length for the given mode and version number.
|
||||
|
||||
### `qrSize(version: number): number`
|
||||
|
||||
Returns the module matrix dimension: `version * 4 + 17`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
All capacity and block tables are lifted verbatim from Annex I of ISO/IEC 18004:2015. Format information strings were independently verified against the reference implementation by cross-checking against the QR code generator specification Table C.1. The `BLOCK_TABLE` entries include zero-count groups (count: 0) to simplify iteration logic in the matrix builder — the builder skips groups with count 0. Version 10 support completes the "versions 1-10" stated scope; versions above 10 are rejected at the API boundary.
|
||||
@@ -0,0 +1,90 @@
|
||||
# qrcode-error
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
`QRCodeError` is the typed error class for the entire `@suaveplan/qrcode` package. It extends the native `Error` class with a stable `code` property drawn from `QRCODE_CODES`, allowing callers to discriminate failure modes programmatically without string parsing. The class intentionally avoids the `@suaveplan/error` dependency so this leaf package remains dependency-minimal: only `zod`, `tslib`, and `@opentelemetry/api` are required at runtime.
|
||||
|
||||
The three error codes cover every failure surface of the QR code generation pipeline: invalid input data, insufficient version capacity for the payload, and unexpected encoding pipeline failures. All three are stable across patch releases.
|
||||
|
||||
## Features
|
||||
|
||||
- `QRCODE_CODES` frozen registry with three stable error codes
|
||||
- `QRCodeCode` union type derived from the registry
|
||||
- `QRCodeError` extends `Error` with a narrow `code: QRCodeCode` property
|
||||
- `instanceof` discrimination for structured error handling
|
||||
- `name` property set to `"QRCodeError"` for logging and stack trace clarity
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { QRCodeError, QRCODE_CODES } from "@suaveplan/qrcode/errors";
|
||||
|
||||
try {
|
||||
throw new QRCodeError("Input is empty", QRCODE_CODES.INVALID_DATA);
|
||||
} catch (err) {
|
||||
if (err instanceof QRCodeError) {
|
||||
console.error(err.code); // "QRCODE.INVALID_DATA"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { QRCodeError, QRCODE_CODES } from "@suaveplan/qrcode/errors";
|
||||
|
||||
function assertVersionCapacity(version: number, byteCount: number): void {
|
||||
// Version 1 byte-mode M capacity = 14 bytes
|
||||
const cap = version === 1 ? 14 : byteCount + 1;
|
||||
if (byteCount > cap) {
|
||||
throw new QRCodeError(
|
||||
`Version ${version} cannot hold ${byteCount} bytes`,
|
||||
QRCODE_CODES.VERSION_TOO_SMALL
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
assertVersionCapacity(1, 20);
|
||||
} catch (err) {
|
||||
if (err instanceof QRCodeError && err.code === QRCODE_CODES.VERSION_TOO_SMALL) {
|
||||
console.warn("Increase version or reduce data size");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `QRCODE_CODES`
|
||||
|
||||
`{ readonly INVALID_DATA: "QRCODE.INVALID_DATA"; readonly VERSION_TOO_SMALL: "QRCODE.VERSION_TOO_SMALL"; readonly ENCODE_FAILED: "QRCODE.ENCODE_FAILED" }`
|
||||
|
||||
Frozen object mapping error-code names to their canonical string values. Consumers should always reference codes via this object rather than inline strings to benefit from rename refactoring and exhaustive switch checking.
|
||||
|
||||
### `QRCodeCode`
|
||||
|
||||
`type QRCodeCode = (typeof QRCODE_CODES)[keyof typeof QRCODE_CODES]`
|
||||
|
||||
Union of all valid error code strings. Narrowed automatically when branching on `err.code`.
|
||||
|
||||
### `class QRCodeError extends Error`
|
||||
|
||||
**Constructor:** `new QRCodeError(message: string, code: QRCodeCode)`
|
||||
|
||||
- `message` — human-readable description of the failure
|
||||
- `code` — one of the values in `QRCODE_CODES`
|
||||
|
||||
**Properties:**
|
||||
|
||||
- `name: "QRCodeError"` — set by the constructor for identification in logs and stack traces
|
||||
- `code: QRCodeCode` — readonly, stable error code
|
||||
- All standard `Error` properties: `message`, `stack`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The class deliberately does not extend `SuaveplanError` from `@suaveplan/error`. This keeps the dependency graph lean: the qrcode package is a leaf in the media domain and should not pull in the full error substrate (Zod wire format, OTel span events, cause-chain traversal) unless a future version explicitly requires them. If the package graduates to depending on `@suaveplan/error`, the migration is straightforward since the `code` property convention is identical.
|
||||
|
||||
The `as const` assertion on `QRCODE_CODES` ensures TypeScript infers string literal types rather than `string`, enabling exhaustive union checks.
|
||||
@@ -0,0 +1,122 @@
|
||||
# qrcode.types
|
||||
|
||||
## Purpose
|
||||
|
||||
Shared TypeScript type definitions for the `@suaveplan/qrcode` package. These types form the public API contract for QR code generation options and results, ensuring consistent interfaces across all modules in the package. All types are consumed by the top-level `generate()` function, renderers, and encoder modules.
|
||||
|
||||
## Features
|
||||
|
||||
- `ErrorCorrectionLevel` — union type for QR error correction levels L, M, Q, and H, each providing a different trade-off between data recovery capacity and payload size
|
||||
- `QRMode` — union type for QR data encoding modes: numeric (digits only), alphanumeric (QR character set), byte (arbitrary UTF-8), and kanji (Shift-JIS)
|
||||
- `OutputFormat` — union type for supported output representations: SVG string, raw boolean matrix, terminal Unicode blocks, and base64 data URL
|
||||
- `QRCodeOptions` — configuration interface for `generate()`, covering EC level, explicit version, quiet zone size, module colors, and pixel scale
|
||||
- `QRCodeResult` — result interface returned by `generate()`, containing all output representations plus metadata (version, EC level, mode, matrix size)
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```typescript
|
||||
import type { QRCodeOptions, QRCodeResult } from "@suaveplan/qrcode";
|
||||
|
||||
const options: QRCodeOptions = {
|
||||
errorCorrectionLevel: "M",
|
||||
margin: 4,
|
||||
color: "#000000",
|
||||
background: "#ffffff",
|
||||
scale: 10,
|
||||
};
|
||||
|
||||
// Pass options to the generate() function
|
||||
// const result: QRCodeResult = generate("Hello World", options);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```typescript
|
||||
import type {
|
||||
ErrorCorrectionLevel,
|
||||
OutputFormat,
|
||||
QRCodeOptions,
|
||||
QRCodeResult,
|
||||
QRMode,
|
||||
} from "@suaveplan/qrcode";
|
||||
|
||||
// Function that accepts strongly-typed parameters
|
||||
function encodeWithLevel(
|
||||
data: string,
|
||||
level: ErrorCorrectionLevel
|
||||
): QRCodeOptions {
|
||||
return {
|
||||
errorCorrectionLevel: level,
|
||||
version: undefined, // auto-select
|
||||
margin: 4,
|
||||
};
|
||||
}
|
||||
|
||||
// Use the result type for structured access
|
||||
function printResult(result: QRCodeResult): void {
|
||||
console.log(`Version: ${result.version}`);
|
||||
console.log(`Mode: ${result.mode satisfies QRMode}`);
|
||||
console.log(`Size: ${result.size}×${result.size}`);
|
||||
console.log(`EC Level: ${result.errorCorrectionLevel satisfies ErrorCorrectionLevel}`);
|
||||
// result.svg, result.dataUrl, result.terminal, result.matrix all available
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `ErrorCorrectionLevel`
|
||||
|
||||
```typescript
|
||||
type ErrorCorrectionLevel = "L" | "M" | "Q" | "H";
|
||||
```
|
||||
|
||||
QR error correction capacity:
|
||||
|
||||
- `"L"` — ~7% data recovery, maximum payload capacity
|
||||
- `"M"` — ~15% data recovery, default level
|
||||
- `"Q"` — ~25% data recovery, balanced
|
||||
- `"H"` — ~30% data recovery, maximum robustness
|
||||
|
||||
### `QRMode`
|
||||
|
||||
```typescript
|
||||
type QRMode = "numeric" | "alphanumeric" | "byte" | "kanji";
|
||||
```
|
||||
|
||||
Data encoding mode. The encoder auto-selects the most compact mode, but callers can inspect the selected mode in `QRCodeResult.mode`.
|
||||
|
||||
### `OutputFormat`
|
||||
|
||||
```typescript
|
||||
type OutputFormat = "svg" | "matrix" | "terminal" | "dataurl";
|
||||
```
|
||||
|
||||
Supported output representations. All four are always present in `QRCodeResult`.
|
||||
|
||||
### `QRCodeOptions`
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `errorCorrectionLevel` | `ErrorCorrectionLevel` | `"M"` | EC level |
|
||||
| `version` | `number` | auto | QR version 1-10 |
|
||||
| `margin` | `number` | `4` | Quiet zone modules |
|
||||
| `color` | `string` | `"#000000"` | Dark module CSS color |
|
||||
| `background` | `string` | `"#ffffff"` | Light module CSS color |
|
||||
| `scale` | `number` | `10` | Pixels per module |
|
||||
|
||||
### `QRCodeResult`
|
||||
|
||||
| Property | Type | Description |
|
||||
|---|---|---|
|
||||
| `version` | `number` | QR version used (1-10) |
|
||||
| `errorCorrectionLevel` | `ErrorCorrectionLevel` | EC level used |
|
||||
| `mode` | `QRMode` | Encoding mode selected |
|
||||
| `matrix` | `boolean[][]` | 2D module matrix; `true` = dark |
|
||||
| `size` | `number` | Matrix dimension in modules |
|
||||
| `svg` | `string` | SVG string representation |
|
||||
| `dataUrl` | `string` | `data:image/svg+xml;base64,...` |
|
||||
| `terminal` | `string` | Unicode half-block terminal art |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
These types are runtime-free (no compiled output), consumed only through `import type`. The `QRCodeOptions` properties are all optional to allow ergonomic partial configuration — each module supplies its own defaults. `QRCodeResult` always includes all output formats so callers do not need to request specific renderers; this avoids conditional rendering logic at the call site.
|
||||
Reference in New Issue
Block a user