feat: tabellengesteuerter Teilenummer-Decoder
Deckt die Samsung-Referenz-Teilenummer aus dem physisch vorhandenen Modul ab. Unbekannte Fragmente (z.B. nicht gelistete Dichte-Codes) liefern bewusst null statt einer Vermutung - das ist der geplante Uebergang zum OCR-Weg, kein Fehlerfall. Das im Task-Brief vorgegebene Regex-Muster liess das literale 'A' der Dichte-Kennung ausserhalb der Erfassungsgruppe, wodurch die Tabellensuche nach 'A8K40' nie greifen konnte. Muster korrigiert, damit die ebenfalls vorgegebenen Tests bestehen; Tabelleninhalte und Warnkommentar blieben wortgleich.
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import { emptySpec, normalizeToken } from './spec.js';
|
||||
import { VENDOR_TABLES } from './pn-tables.js';
|
||||
|
||||
/**
|
||||
* Leitet aus einer Hersteller-Teilenummer die Spec-Felder ab.
|
||||
* Nicht ableitbare Felder bleiben null - das ist kein Fehler,
|
||||
* sondern der regulaere Uebergang zum OCR-Weg.
|
||||
*/
|
||||
export function decodePartNumber(pn) {
|
||||
const spec = emptySpec();
|
||||
const normalized = normalizeToken(pn);
|
||||
if (normalized === '') return spec;
|
||||
|
||||
spec.partNumber = normalized;
|
||||
|
||||
for (const table of VENDOR_TABLES) {
|
||||
const match = normalized.match(table.pattern);
|
||||
if (!match) continue;
|
||||
|
||||
const [, formCode, densityCode, speedCode] = match;
|
||||
|
||||
spec.formFactor = table.formFactor[formCode] ?? null;
|
||||
spec.speed = table.speed[speedCode] ?? null;
|
||||
|
||||
const density = table.density[densityCode];
|
||||
if (density) {
|
||||
spec.capacityGb = density.capacityGb;
|
||||
spec.rank = density.rank;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return spec;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Herstellertabellen fuer den Teilenummer-Decoder.
|
||||
//
|
||||
// ACHTUNG: Nur der Samsung-Eintrag 'A8K40' und der Geschwindigkeitscode 'CRC'
|
||||
// sind gegen ein reales Modul geprueft (64GB 4DRx4 PC4-2400T LRDIMM,
|
||||
// M386A8K40BM1-CRC4Y). Alle uebrigen Eintraege stammen aus der veroeffentlichten
|
||||
// Systematik und muessen vor produktivem Einsatz gegen reale Module bestaetigt
|
||||
// werden - siehe Task 14. Ein falscher Eintrag faellt beim Sortieren dadurch
|
||||
// auf, dass der OCR-Klartext dem dekodierten Wert widerspricht.
|
||||
|
||||
export const VENDOR_TABLES = [
|
||||
{
|
||||
vendor: 'Samsung',
|
||||
// M<bauform><dichte>-<rev(3)>-<speed><rest>
|
||||
// Hinweis: Die im Brief angegebene Fassung dieses Musters liess die
|
||||
// fuehrende Generationskennung 'A' ausserhalb der Erfassungsgruppe und
|
||||
// erfasste dadurch nie den vollstaendigen Dichte-Code 'A8K40' - die
|
||||
// Tabellensuche schlug immer fehl. Hier korrigiert: 'A' gehoert zur
|
||||
// erfassten Dichte-Gruppe, die Revision hat feste Laenge 3.
|
||||
pattern: /^M(\d{3})(A[A-Z0-9]{4})[A-Z0-9]{3}-([A-Z]{3})/,
|
||||
formFactor: {
|
||||
378: 'UDIMM',
|
||||
391: 'UDIMM',
|
||||
393: 'RDIMM',
|
||||
386: 'LRDIMM',
|
||||
471: 'SODIMM',
|
||||
474: 'SODIMM',
|
||||
},
|
||||
density: {
|
||||
// geprueft am Referenzmodul:
|
||||
A8K40: { capacityGb: 64, rank: '4DRx4' },
|
||||
},
|
||||
speed: {
|
||||
CPB: 'PC4-2133',
|
||||
CRC: 'PC4-2400',
|
||||
CTD: 'PC4-2666',
|
||||
CVF: 'PC4-2933',
|
||||
CWE: 'PC4-3200',
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,41 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { decodePartNumber } from '../src/pn-decoder.js';
|
||||
|
||||
test('dekodiert die Samsung-Teilenummer aus dem Referenzmodul', () => {
|
||||
const spec = decodePartNumber('M386A8K40BM1-CRC4Y');
|
||||
assert.equal(spec.formFactor, 'LRDIMM');
|
||||
assert.equal(spec.speed, 'PC4-2400');
|
||||
assert.equal(spec.capacityGb, 64);
|
||||
assert.equal(spec.rank, '4DRx4');
|
||||
assert.equal(spec.partNumber, 'M386A8K40BM1-CRC4Y');
|
||||
});
|
||||
|
||||
test('erkennt die Bauform auch ohne bekannten Dichte-Code', () => {
|
||||
const spec = decodePartNumber('M393A2K43BB1-CTD');
|
||||
assert.equal(spec.formFactor, 'RDIMM');
|
||||
assert.equal(spec.speed, 'PC4-2666');
|
||||
assert.equal(spec.capacityGb, null, 'unbekannter Dichte-Code laesst das Feld offen');
|
||||
assert.equal(spec.rank, null);
|
||||
assert.equal(spec.partNumber, 'M393A2K43BB1-CTD');
|
||||
});
|
||||
|
||||
test('normalisiert Kleinschreibung und Leerzeichen', () => {
|
||||
const spec = decodePartNumber(' m386a8k40bm1-crc4y ');
|
||||
assert.equal(spec.capacityGb, 64);
|
||||
assert.equal(spec.partNumber, 'M386A8K40BM1-CRC4Y');
|
||||
});
|
||||
|
||||
test('unbekannter Hersteller liefert ein leeres Spec mit gesetzter Teilenummer', () => {
|
||||
const spec = decodePartNumber('7325773');
|
||||
assert.equal(spec.formFactor, null);
|
||||
assert.equal(spec.speed, null);
|
||||
assert.equal(spec.capacityGb, null);
|
||||
assert.equal(spec.partNumber, '7325773');
|
||||
});
|
||||
|
||||
test('leere Eingabe liefert ein vollstaendig leeres Spec', () => {
|
||||
const spec = decodePartNumber('');
|
||||
assert.equal(spec.partNumber, null);
|
||||
assert.equal(spec.capacityGb, null);
|
||||
});
|
||||
Reference in New Issue
Block a user