diff --git a/src/scan-modes.js b/src/scan-modes.js new file mode 100644 index 0000000..e275bd4 --- /dev/null +++ b/src/scan-modes.js @@ -0,0 +1,68 @@ +// Die drei Scan-Funktionen, die der Nutzer vor dem Scannen waehlt. Reines +// Modul ohne Browser-Zugriff (kein window/document/navigator) - einzige +// Quelle fuer Kennung, Beschriftung, Codearten und Verhalten je Funktion. +// Sowohl die Auswahl-Oberflaeche als auch main.js lesen ausschliesslich von +// hier - es darf keine zweite Stelle geben, an der Codearten oder +// Beschriftungen stehen. +// +// Ausdrueckliche Entscheidung des Auftraggebers (nicht abaendern): Funktion 2 +// liest streng nur QR (QRCode, MicroQRCode, RMQRCode) - kein DataMatrix, auch +// wenn die 2D-Codes auf den eigenen RAM-Etiketten DataMatrix sind. Der +// Arbeitsablauf des Auftraggebers laeuft ueber Funktion 1 (Teilenummer im +// Strichcode); Funktion 2 dient anderer Ware. + +/** + * @typedef {object} ScanMode + * @property {string} id Kennung, intern verwendet (main.js, Speicherung der Wahl). + * @property {string} label Deutsche Beschriftung fuer die Oberflaeche. + * @property {string[]} barcodeFormats An decodeBarcodes() zu uebergebende + * Codearten (zxing-wasm-Formatnamen). Leer, wenn die Funktion keine + * Barcode-Dekodierung nutzt. + * @property {boolean} continuousSearch Ob waehrend die Kamera laeuft + * fortwaehrend nach Codes gesucht wird (statt nur auf Knopfdruck). + * @property {boolean} useOcr Ob die Texterkennung (Tesseract) genutzt wird. + */ + +/** @type {ScanMode[]} */ +export const SCAN_MODES = [ + { + id: 'barcode', + label: 'Strichcode', + // Eindimensionale Codes, wie sie auf Teilenummern-Etiketten vorkommen. + barcodeFormats: ['Code128', 'Code39', 'Code93', 'ITF', 'EAN13', 'EAN8', 'UPCA', 'UPCE', 'Codabar'], + continuousSearch: true, + useOcr: false, + }, + { + id: 'qrcode', + label: 'QR-Code', + // Ausschliesslich QR-Varianten - bewusst kein DataMatrix, siehe Kommentar oben. + barcodeFormats: ['QRCode', 'MicroQRCode', 'RMQRCode'], + continuousSearch: true, + useOcr: false, + }, + { + id: 'ocr', + label: 'Text erkennen', + // Keine Codes - allein die Texterkennung, auf Knopfdruck. + barcodeFormats: [], + continuousSearch: false, + useOcr: true, + }, +]; + +/** + * Liefert die Funktion zu einer Kennung. + * @param {string} id + * @returns {ScanMode} + * @throws {Error} wenn die Kennung keiner der drei Funktionen entspricht - + * ein Programmfehler (main.js darf nie eine fremde Kennung durchreichen), + * kein regulaerer Ausgang. + */ +export function getScanMode(id) { + const mode = SCAN_MODES.find((candidate) => candidate.id === id); + if (!mode) { + throw new Error(`Unbekannte Scan-Funktion: ${id}`); + } + return mode; +} diff --git a/test/scan-modes.test.js b/test/scan-modes.test.js new file mode 100644 index 0000000..5eef09c --- /dev/null +++ b/test/scan-modes.test.js @@ -0,0 +1,39 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { SCAN_MODES, getScanMode } from '../src/scan-modes.js'; + +test('genau drei Funktionen in fester Reihenfolge', () => { + assert.equal(SCAN_MODES.length, 3); + assert.deepEqual(SCAN_MODES.map((mode) => mode.id), ['barcode', 'qrcode', 'ocr']); +}); + +test('Funktion 1 (Strichcode): eindimensionale Codearten, laufende Suche, keine Texterkennung', () => { + const mode = getScanMode('barcode'); + assert.equal(mode.label, 'Strichcode'); + assert.deepEqual(mode.barcodeFormats, [ + 'Code128', 'Code39', 'Code93', 'ITF', 'EAN13', 'EAN8', 'UPCA', 'UPCE', 'Codabar', + ]); + assert.equal(mode.continuousSearch, true); + assert.equal(mode.useOcr, false); +}); + +test('Funktion 2 (QR-Code): ausschliesslich QR-Varianten, kein DataMatrix', () => { + const mode = getScanMode('qrcode'); + assert.equal(mode.label, 'QR-Code'); + assert.deepEqual(mode.barcodeFormats, ['QRCode', 'MicroQRCode', 'RMQRCode']); + assert.ok(!mode.barcodeFormats.includes('DataMatrix'), 'Funktion 2 darf kein DataMatrix lesen'); + assert.equal(mode.continuousSearch, true); + assert.equal(mode.useOcr, false); +}); + +test('Funktion 3 (Text erkennen): keine Codearten, keine laufende Suche, Texterkennung', () => { + const mode = getScanMode('ocr'); + assert.equal(mode.label, 'Text erkennen'); + assert.deepEqual(mode.barcodeFormats, []); + assert.equal(mode.continuousSearch, false); + assert.equal(mode.useOcr, true); +}); + +test('unbekannte Kennung wirft statt undefined zurueckzugeben', () => { + assert.throws(() => getScanMode('unbekannt')); +});