Bug: MessageDecoder.decode discards default failure result when no plugin decodes
bug
## Summary
`MessageDecoder.decode()` builds a sensible default `result` for the "no plugin matched" case (with `error: 'No known decoder plugin for this message'`, the original `message`, full `remaining.text`, and `decoder: { name: 'none', ... }`), but then unconditionally **overwrites** that `result` with the return value of every plugin in the loop. If no plugin sets `decoded: true`, callers get the *last* plugin's return value — which has none of the diagnostic fields.
## Affected code
`lib/MessageDecoder.ts` — the decode loop:
```ts
let result: DecodeResult = {
decoded: false,
error: 'No known decoder plugin for this message',
decoder: { name: 'none', type: 'none', decodeLevel: 'none' },
message: message,
remaining: { text: message.text },
raw: {},
formatted: { description: 'Not Decoded', items: [] },
};
for (let i = 0; i < usablePlugins.length; i++) {
const plugin = usablePlugins[i];
result = plugin.decode(message, options); // overwrites the default
if (result.decoded) {
break;
}
}
return result;
```
When the loop finishes without a successful decode, `result` is whatever the **last** plugin returned. Per `DecoderPlugin.defaultResult()`, that result has:
- no `error` field
- no `message` field
- `decoder.name` set to the *plugin* name (e.g. `"label-44-pos"`), suggesting falsely that that plugin handled the message
- `formatted.description` set to `"Unknown"` rather than `"Not Decoded"`
## Reproduction
Pass a message with a registered label whose payload doesn't match any plugin's pattern (e.g. label `44` with garbage text). The returned `decoder.name` will be the last `Label_44_*` plugin tried, and `error` / `message` will be missing.
## Suggested fix
Track plugin returns in a temporary and only overwrite the default on a successful decode (or merge the diagnostic fields):
```ts
for (const plugin of usablePlugins) {
const r = plugin.decode(message, options);
if (r.decoded) {
result = r;
break;
}
}
return result;
```
This also matches the "no plugin matched" semantics that the default object clearly intends.
0 条评论