來源格式與預期記錄
這是原創假設轉換例子。輸入限下列欄位的普通、無循環 JSON 形記錄,統一記錄格式及拒絕代碼由本例訂明。若換來源,先修改格式約定。
本例樹的葉節點是非空結果文字;其他節點要有 if、then、else,if 指布林條件。沿每分支保存真/假條件,欠分支或同一路徑重查同欄便拒絕。只有結果文字則產生一條無條件路徑。
| 個案 | 輸入記錄(JSON) | 預期輸出(JSON) |
|---|---|---|
| 整理原訂分支樹 | {"tree":{"if":"urgent","then":"fast","else":{"if":"special","then":"specialist","else":"normal"}}} | {"ok":true,"value":{"paths":[{"conditions":[{"field":"urgent","is":true}],"outcome":"fast"},{"conditions":[{"field":"urgent","is":false},{"field":"special","is":true}],"outcome":"specialist"},{"conditions":[{"field":"urgent","is":false},{"field":"special","is":false}],"outcome":"normal"}]}} |
| 拒絕欠分支 | {"tree":{"if":"urgent","then":"fast"}} | {"ok":false,"error":"TREE_NODE"} |
| 保留無條件結果 | {"tree":"manual"} | {"ok":true,"value":{"paths":[{"conditions":[],"outcome":"manual"}]}} |
在本機執行轉換
把完整例子以 JavaScript 模組在 Node.js 執行,內含純轉換函數、三個輸入及寫明的預期輸出,對不上便由斷言停止。拒絕個案回傳 ok=false 及代碼,不回傳半份統一記錄。
import assert from 'node:assert/strict';
function decisionPaths(i){
const fail=error=>({ok:false,error});if(!i||!Object.hasOwn(i,'tree'))return fail('TREE_MISSING');
const paths=[];let error;
const walk=(node,conditions,used)=>{
if(typeof node==='string'){if(!node){error='TREE_OUTCOME';return;}paths.push({conditions,outcome:node});return;}
if(!node||typeof node!=='object'||Array.isArray(node)||typeof node.if!=='string'||!node.if||!Object.hasOwn(node,'then')||!Object.hasOwn(node,'else')){error='TREE_NODE';return;}
if(used.has(node.if)){error='TREE_REPEAT';return;}
const next=new Set(used);next.add(node.if);
walk(node.then,[...conditions,{field:node.if,is:true}],next);
walk(node.else,[...conditions,{field:node.if,is:false}],next);
};
walk(i.tree,[],new Set());return error?fail(error):{ok:true,value:{paths}};
}
// Original synthetic cases; expected outputs are literal records.
const cases = [
{
"label": "Flatten original branch tree",
"input": {
"tree": {
"if": "urgent",
"then": "fast",
"else": {
"if": "special",
"then": "specialist",
"else": "normal"
}
}
},
"expected": {
"ok": true,
"value": {
"paths": [
{
"conditions": [
{
"field": "urgent",
"is": true
}
],
"outcome": "fast"
},
{
"conditions": [
{
"field": "urgent",
"is": false
},
{
"field": "special",
"is": true
}
],
"outcome": "specialist"
},
{
"conditions": [
{
"field": "urgent",
"is": false
},
{
"field": "special",
"is": false
}
],
"outcome": "normal"
}
]
}
}
},
{
"label": "Reject missing branch",
"input": {
"tree": {
"if": "urgent",
"then": "fast"
}
},
"expected": {
"ok": false,
"error": "TREE_NODE"
}
},
{
"label": "Preserve unconditional outcome",
"input": {
"tree": "manual"
},
"expected": {
"ok": true,
"value": {
"paths": [
{
"conditions": [],
"outcome": "manual"
}
]
}
}
}
];
for (const sample of cases) {
const actual = decisionPaths(sample.input);
assert.deepEqual(actual, sample.expected);
console.log(sample.label, JSON.stringify(actual));
}
判清邊界個案
首個案要甚麼條件才到 specialist?
查看參考答案
先 urgent=false,再 special=true。fast 只要 urgent=true;normal 要 urgent=false 且 special=false。三條路徑描述來源樹,尚未執行判定。