* Marshals a JS value into XML under the `wd:` namespace. * Conventions: * - Plain objects become elements with named children * - `attributes` becomes element attributes * - `$value` (or `_`) provides the element text content * - Arrays produce repeated elements with the same name * - Bo
(name: string, value: unknown)
| 236 | * - Booleans render as "true"/"false", numbers via String() |
| 237 | */ |
| 238 | function marshal(name: string, value: unknown): string { |
| 239 | if (value === undefined || value === null) return '' |
| 240 | const tag = `wd:${name}` |
| 241 | |
| 242 | if (Array.isArray(value)) { |
| 243 | let out = '' |
| 244 | for (const item of value) { |
| 245 | out += marshal(name, item) |
| 246 | } |
| 247 | return out |
| 248 | } |
| 249 | |
| 250 | if (value instanceof Date) { |
| 251 | return `<${tag}>${value.toISOString()}</${tag}>` |
| 252 | } |
| 253 | |
| 254 | if (typeof value === 'object') { |
| 255 | const obj = value as Record<string, unknown> |
| 256 | const attrs = obj.attributes as Record<string, string> | undefined |
| 257 | const text = (obj.$value ?? obj._) as string | number | boolean | undefined |
| 258 | |
| 259 | if (text !== undefined) { |
| 260 | const childKeys = Object.keys(obj).filter( |
| 261 | (k) => k !== 'attributes' && k !== '$value' && k !== '_' |
| 262 | ) |
| 263 | if (childKeys.length === 0) { |
| 264 | return `<${tag}${serializeAttributes(attrs)}>${escapeXml(String(text))}</${tag}>` |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | let inner = '' |
| 269 | for (const [k, v] of Object.entries(obj)) { |
| 270 | if (k === 'attributes' || k === '$value' || k === '_') continue |
| 271 | inner += marshal(k, v) |
| 272 | } |
| 273 | if (text !== undefined) inner = escapeXml(String(text)) + inner |
| 274 | return `<${tag}${serializeAttributes(attrs)}>${inner}</${tag}>` |
| 275 | } |
| 276 | |
| 277 | if (typeof value === 'boolean') { |
| 278 | return `<${tag}>${value ? 'true' : 'false'}</${tag}>` |
| 279 | } |
| 280 | |
| 281 | return `<${tag}>${escapeXml(String(value))}</${tag}>` |
| 282 | } |
| 283 | |
| 284 | function buildEnvelope( |
| 285 | operation: string, |
no test coverage detected