Source contract and expected records
This is an original, fully synthetic mapping example. Inputs are plain, acyclic JSON-shaped records with the fields shown; the canonical shape and rejection codes belong to this example. Adapt the contract before using a different source.
Contacts declare email or phone, nonempty value text and an explicit Boolean preferred flag. At most one may be preferred. Put that entry in preferred and others in alternates. If none is selected, preferred=null and all remain alternatives. Values are copied without verification or sending.
| Case | Input record (JSON) | Expected output (JSON) |
|---|---|---|
| Separate preferred and alternate | {"contacts":[{"type":"email","value":"ada@example.invalid","preferred":true},{"type":"phone","value":"+000 1234","preferred":false}]} | {"ok":true,"value":{"preferred":{"type":"email","value":"ada@example.invalid"},"alternates":[{"type":"phone","value":"+000 1234"}]}} |
| Reject competing preferred contacts | {"contacts":[{"type":"email","value":"a@example.invalid","preferred":true},{"type":"email","value":"b@example.invalid","preferred":true}]} | {"ok":false,"error":"CONTACT_PREFERENCE"} |
| Preserve no preference | {"contacts":[{"type":"email","value":"a@example.invalid","preferred":false}]} | {"ok":true,"value":{"preferred":null,"alternates":[{"type":"email","value":"a@example.invalid"}]}} |
Run the local transformation
Run the complete example as a JavaScript module in Node.js. It contains the pure mapping function, all three inputs and literal expected outputs; assertions stop on a mismatch. A rejected case returns ok=false with an error code, rather than a partial canonical record.
import assert from 'node:assert/strict';
function preferredContact(i){
const fail=error=>({ok:false,error});if(!i||!Array.isArray(i.contacts))return fail('CONTACT_LIST');
if(i.contacts.some(c=>!c||!['email','phone'].includes(c.type)||typeof c.value!=='string'||!c.value||typeof c.preferred!=='boolean'))return fail('CONTACT_VALUE');
if(i.contacts.filter(c=>c.preferred).length>1)return fail('CONTACT_PREFERENCE');
const preferred=i.contacts.find(c=>c.preferred);
return {ok:true,value:{preferred:preferred?{type:preferred.type,value:preferred.value}:null,alternates:i.contacts.filter(c=>!c.preferred).map(c=>({type:c.type,value:c.value}))}};
}
// Original synthetic cases; expected outputs are literal records.
const cases = [
{
"label": "Separate preferred and alternate",
"input": {
"contacts": [
{
"type": "email",
"value": "ada@example.invalid",
"preferred": true
},
{
"type": "phone",
"value": "+000 1234",
"preferred": false
}
]
},
"expected": {
"ok": true,
"value": {
"preferred": {
"type": "email",
"value": "ada@example.invalid"
},
"alternates": [
{
"type": "phone",
"value": "+000 1234"
}
]
}
}
},
{
"label": "Reject competing preferred contacts",
"input": {
"contacts": [
{
"type": "email",
"value": "a@example.invalid",
"preferred": true
},
{
"type": "email",
"value": "b@example.invalid",
"preferred": true
}
]
},
"expected": {
"ok": false,
"error": "CONTACT_PREFERENCE"
}
},
{
"label": "Preserve no preference",
"input": {
"contacts": [
{
"type": "email",
"value": "a@example.invalid",
"preferred": false
}
]
},
"expected": {
"ok": true,
"value": {
"preferred": null,
"alternates": [
{
"type": "email",
"value": "a@example.invalid"
}
]
}
}
}
];
for (const sample of cases) {
const actual = preferredContact(sample.input);
assert.deepEqual(actual, sample.expected);
console.log(sample.label, JSON.stringify(actual));
}
Work through the boundary
If two entries both say preferred=true, can the first simply win?
Show the worked answer
No. CONTACT_PREFERENCE reports the conflict. With no preference, the preservation case instead returns null and retains every alternative rather than selecting by list order.