來源格式與預期記錄
這是原創假設轉換例子。輸入限下列欄位的普通、無循環 JSON 形記錄,統一記錄格式及拒絕代碼由本例訂明。若換來源,先修改格式約定。
本例有兩種自訂來源格式,type 明列 goods 或 service,另填 description。goods 要非負安全整數 units 及非空 unitLabel,轉入 quantity;service 要 deliverables 文字清單且不能有 units,轉入 deliverables。這是本例格式限制,不是所有服務銷售的通則。
| 個案 | 輸入記錄(JSON) | 預期輸出(JSON) |
|---|---|---|
| 建立貨品數量記錄 | {"type":"goods","description":"Panels","units":3,"unitLabel":"piece"} | {"ok":true,"value":{"kind":"goods","description":"Panels","quantity":{"units":3,"unit":"piece"}}} |
| 拒絕服務格式混入貨品件數 | {"type":"service","description":"Setup","units":3,"deliverables":["Guide"]} | {"ok":false,"error":"SERVICE_QUANTITY"} |
| 保留服務交付清單 | {"type":"service","description":"Setup","deliverables":[]} | {"ok":true,"value":{"kind":"service","description":"Setup","deliverables":[]}} |
在本機執行轉換
把完整例子以 JavaScript 模組在 Node.js 執行,內含純轉換函數、三個輸入及寫明的預期輸出,對不上便由斷言停止。拒絕個案回傳 ok=false 及代碼,不回傳半份統一記錄。
import assert from 'node:assert/strict';
function goodsServiceLine(i){
const fail=error=>({ok:false,error});if(!i||typeof i.description!=='string'||!i.description)return fail('LINE_DESCRIPTION');
if(i.type==='goods'){
if(!Number.isSafeInteger(i.units)||i.units<0||typeof i.unitLabel!=='string'||!i.unitLabel)return fail('GOODS_QUANTITY');
return {ok:true,value:{kind:'goods',description:i.description,quantity:{units:i.units,unit:i.unitLabel}}};
}
if(i.type==='service'){
if(Object.hasOwn(i,'units'))return fail('SERVICE_QUANTITY');
if(!Array.isArray(i.deliverables)||i.deliverables.some(x=>typeof x!=='string'||!x))return fail('SERVICE_DELIVERABLES');
return {ok:true,value:{kind:'service',description:i.description,deliverables:[...i.deliverables]}};
}
return fail('LINE_TYPE');
}
// Original synthetic cases; expected outputs are literal records.
const cases = [
{
"label": "Construct goods quantity record",
"input": {
"type": "goods",
"description": "Panels",
"units": 3,
"unitLabel": "piece"
},
"expected": {
"ok": true,
"value": {
"kind": "goods",
"description": "Panels",
"quantity": {
"units": 3,
"unit": "piece"
}
}
}
},
{
"label": "Reject physical units on service shape",
"input": {
"type": "service",
"description": "Setup",
"units": 3,
"deliverables": [
"Guide"
]
},
"expected": {
"ok": false,
"error": "SERVICE_QUANTITY"
}
},
{
"label": "Preserve service deliverable list",
"input": {
"type": "service",
"description": "Setup",
"deliverables": []
},
"expected": {
"ok": true,
"value": {
"kind": "service",
"description": "Setup",
"deliverables": []
}
}
}
];
for (const sample of cases) {
const actual = goodsServiceLine(sample.input);
assert.deepEqual(actual, sample.expected);
console.log(sample.label, JSON.stringify(actual));
}
判清邊界個案
服務的 deliverables 是空清單,怎樣處理?
查看參考答案
仍保留服務記錄及 deliverables=[]。服務若另有 units 則以 SERVICE_QUANTITY 拒絕,不改猜為貨品。