來源格式與預期記錄
這是原創假設轉換例子。輸入限下列欄位的普通、無循環 JSON 形記錄,統一記錄格式及拒絕代碼由本例訂明。若換來源,先修改格式約定。
非空 base 字樣配 option 清單,key、value 都非空,key 不可重複。本例 variant 只收 colour、finish、size;其他項目放 unmapped,不刪除。任何 key 重複都拒絕,包括未知 key。
| 個案 | 輸入記錄(JSON) | 預期輸出(JSON) |
|---|---|---|
| 整理已定選項鍵 | {"base":"A","options":[{"key":"colour","value":"blue"},{"key":"finish","value":"matte"}]} | {"ok":true,"value":{"base":"A","variant":{"colour":"blue","finish":"matte"},"unmapped":[]}} |
| 拒絕重複選項鍵 | {"base":"A","options":[{"key":"colour","value":"blue"},{"key":"colour","value":"red"}]} | {"ok":false,"error":"VARIANT_DUPLICATE"} |
| 保留未定選項 | {"base":"A","options":[{"key":"material","value":"paper"}]} | {"ok":true,"value":{"base":"A","variant":{},"unmapped":[{"key":"material","value":"paper"}]}} |
在本機執行轉換
把完整例子以 JavaScript 模組在 Node.js 執行,內含純轉換函數、三個輸入及寫明的預期輸出,對不上便由斷言停止。拒絕個案回傳 ok=false 及代碼,不回傳半份統一記錄。
import assert from 'node:assert/strict';
function variantOptions(i){
const fail=error=>({ok:false,error});if(!i||typeof i.base!=='string'||!i.base||!Array.isArray(i.options))return fail('VARIANT_SHAPE');
const variant={},unmapped=[],keys=new Set();
for(const o of i.options){
if(!o||typeof o.key!=='string'||!o.key||typeof o.value!=='string'||!o.value)return fail('VARIANT_VALUE');
if(keys.has(o.key))return fail('VARIANT_DUPLICATE');keys.add(o.key);
if(['colour','finish','size'].includes(o.key))variant[o.key]=o.value;else unmapped.push({key:o.key,value:o.value});
}
return {ok:true,value:{base:i.base,variant,unmapped}};
}
// Original synthetic cases; expected outputs are literal records.
const cases = [
{
"label": "Map declared option keys",
"input": {
"base": "A",
"options": [
{
"key": "colour",
"value": "blue"
},
{
"key": "finish",
"value": "matte"
}
]
},
"expected": {
"ok": true,
"value": {
"base": "A",
"variant": {
"colour": "blue",
"finish": "matte"
},
"unmapped": []
}
}
},
{
"label": "Reject repeated option key",
"input": {
"base": "A",
"options": [
{
"key": "colour",
"value": "blue"
},
{
"key": "colour",
"value": "red"
}
]
},
"expected": {
"ok": false,
"error": "VARIANT_DUPLICATE"
}
},
{
"label": "Preserve undeclared option",
"input": {
"base": "A",
"options": [
{
"key": "material",
"value": "paper"
}
]
},
"expected": {
"ok": true,
"value": {
"base": "A",
"variant": {},
"unmapped": [
{
"key": "material",
"value": "paper"
}
]
}
}
}
];
for (const sample of cases) {
const actual = variantOptions(sample.input);
assert.deepEqual(actual, sample.expected);
console.log(sample.label, JSON.stringify(actual));
}
判清邊界個案
只有 material=paper,沒有已知選項,資料去哪裏?
查看參考答案
variant 保持 {},material/paper 配對放 unmapped,base 也保存。不會由選項文字自行編出新 SKU。