xml-model 2.0.0-beta.1 → 2.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/xml/codec.js CHANGED
@@ -1,385 +1,339 @@
1
- import { z } from "zod";
2
- import { XML } from "./xml-js.js";
1
+ import XML from "./xml-js.js";
2
+ import { isZodType } from "../util/zod.js";
3
3
  import { getUserOptions } from "./schema-meta.js";
4
4
  import { kebabCase } from "../util/kebab-case.js";
5
- import { isZodType } from "../util/zod.js";
5
+ import { z } from "zod";
6
+ //#region src/xml/codec.ts
6
7
  function assertSingleElement(xml) {
7
- if (xml.length !== 1) throw new Error(`Expected single XML element, got ${xml.length}`);
8
- }
9
- function assertSingleRoot(xml) {
10
- assertSingleElement(xml);
11
- if (!Array.isArray(xml[0].elements)) throw new Error(`Expected element with children list`);
8
+ if (xml.length !== 1) throw new Error(`Expected single XML element, got ${xml.length}`);
12
9
  }
13
10
  function normalizeCodecOptions(schema, options = {}) {
14
- let _defaultOptions;
15
- const defaultOptions = () => {
16
- if (!_defaultOptions) {
17
- _defaultOptions = resolveDefault(schema);
18
- if (!_defaultOptions) {
19
- throw new Error(
20
- `Failed to resolve default codec options for schema of type ${schema.type}`
21
- );
22
- }
23
- }
24
- return _defaultOptions;
25
- };
26
- const userTagname = options.tagname;
27
- const tagname = typeof userTagname === "string" ? () => userTagname : typeof userTagname === "function" ? userTagname : () => {
28
- throw new Error("tagname is not defined");
29
- };
30
- const userPropTagname = options.propertyTagname;
31
- const propertyTagname = typeof userPropTagname === "string" ? () => userPropTagname : typeof userPropTagname === "function" ? userPropTagname : (ctx) => kebabCase(ctx.name);
32
- const inlineProperty = options.inlineProperty ?? false;
33
- const userMatch = options.propertyMatch;
34
- const propertyMatch = userMatch instanceof RegExp ? (el) => userMatch.test(el.name) : typeof userMatch === "function" ? userMatch : (el, ctx) => el.name === ctx.tagname;
35
- const decode2 = options.decode ?? defaultOptions().decode;
36
- const encode2 = options.encode ?? defaultOptions().encode;
37
- const result = {
38
- schema,
39
- tagname,
40
- decode: decode2,
41
- encode: encode2,
42
- propertyTagname,
43
- inlineProperty,
44
- propertyMatch,
45
- decodeAsProperty: options.decodeAsProperty ?? function(ctx) {
46
- const res = result.decode({ options: result, xml: ctx.property.xml });
47
- ctx.result[ctx.property.name] = res;
48
- },
49
- encodeAsProperty: options.encodeAsProperty ?? function(ctx) {
50
- const { property } = ctx;
51
- const optsWithTagname = { ...result, tagname: () => property.tagname };
52
- const res = result.encode({
53
- options: optsWithTagname,
54
- // FIXME: we should not rely on type casting
55
- data: property.value
56
- });
57
- if (XML.isEmpty(res)) {
58
- return;
59
- }
60
- if (property.options.inlineProperty) {
61
- ctx.result.elements.push(...res.elements);
62
- } else {
63
- ctx.result.elements.push(res);
64
- }
65
- }
66
- };
67
- return result;
11
+ let _defaultOptions;
12
+ const defaultOptions = () => {
13
+ if (!_defaultOptions) {
14
+ _defaultOptions = resolveDefault(schema);
15
+ if (!_defaultOptions) throw new Error(`Failed to resolve default codec options for schema of type ${schema.type}`);
16
+ }
17
+ return _defaultOptions;
18
+ };
19
+ const userTagname = options.tagname;
20
+ const tagname = typeof userTagname === "string" ? () => userTagname : typeof userTagname === "function" ? userTagname : () => {
21
+ throw new Error("tagname is not defined");
22
+ };
23
+ const userPropTagname = options.propertyTagname;
24
+ const propertyTagname = typeof userPropTagname === "string" ? () => userPropTagname : typeof userPropTagname === "function" ? userPropTagname : (ctx) => kebabCase(ctx.name);
25
+ const inlineProperty = options.inlineProperty ?? false;
26
+ const userMatch = options.propertyMatch;
27
+ const propertyMatch = userMatch instanceof RegExp ? (el) => userMatch.test(el.name) : typeof userMatch === "function" ? userMatch : (el, ctx) => el.name === ctx.tagname;
28
+ const result = {
29
+ schema,
30
+ tagname,
31
+ decode: options.decode ?? defaultOptions().decode,
32
+ encode: options.encode ?? defaultOptions().encode,
33
+ propertyTagname,
34
+ inlineProperty,
35
+ propertyMatch,
36
+ decodeAsProperty: options.decodeAsProperty ?? function(ctx) {
37
+ const res = result.decode({
38
+ options: result,
39
+ xml: ctx.property.xml
40
+ });
41
+ ctx.result[ctx.property.name] = res;
42
+ },
43
+ encodeAsProperty: options.encodeAsProperty ?? function(ctx) {
44
+ const { property } = ctx;
45
+ const optsWithTagname = {
46
+ ...result,
47
+ tagname: () => property.tagname
48
+ };
49
+ const res = result.encode({
50
+ options: optsWithTagname,
51
+ data: property.value
52
+ });
53
+ if (XML.isEmpty(res)) return;
54
+ if (property.options.inlineProperty) ctx.result.elements.push(...res.elements);
55
+ else ctx.result.elements.push(res);
56
+ }
57
+ };
58
+ return result;
68
59
  }
69
- const cache = /* @__PURE__ */ new Map();
60
+ var cache = /* @__PURE__ */ new Map();
70
61
  function resolveCodecOptions(schema) {
71
- const cached = cache.get(schema);
72
- if (cached) return cached;
73
- const userOpts = getUserOptions(schema);
74
- const options = normalizeCodecOptions(schema, userOpts);
75
- cache.set(schema, options);
76
- return options;
62
+ const cached = cache.get(schema);
63
+ if (cached) return cached;
64
+ const options = normalizeCodecOptions(schema, getUserOptions(schema));
65
+ cache.set(schema, options);
66
+ return options;
77
67
  }
78
- const XML_STATE = /* @__PURE__ */ Symbol("xml-model.state");
68
+ /**
69
+ * Non-enumerable Symbol attached to decoded data objects (and forwarded to model instances).
70
+ * Groups all XML codec round-trip state under a single key.
71
+ */
72
+ var XML_STATE = Symbol("xml-model.state");
79
73
  function resolvePropertiesCodecOptions(schema) {
80
- const shape = schema.def.shape;
81
- const options = {};
82
- for (const [prop, fieldSchema] of Object.entries(shape)) {
83
- options[prop] = resolveCodecOptions(fieldSchema);
84
- }
85
- return options;
74
+ const shape = schema.def.shape;
75
+ const options = {};
76
+ for (const [prop, fieldSchema] of Object.entries(shape)) options[prop] = resolveCodecOptions(fieldSchema);
77
+ return options;
86
78
  }
87
79
  function decode(schema, xml) {
88
- const options = resolveCodecOptions(schema);
89
- return options.decode({ options, xml });
80
+ const options = resolveCodecOptions(schema);
81
+ return options.decode({
82
+ options,
83
+ xml
84
+ });
90
85
  }
91
86
  function encode(schema, data) {
92
- const options = resolveCodecOptions(schema);
93
- return options.encode({ options, data });
87
+ const options = resolveCodecOptions(schema);
88
+ return options.encode({
89
+ options,
90
+ data
91
+ });
94
92
  }
95
93
  function registerDefault(resolve) {
96
- defaults.push(resolve);
94
+ defaults.push(resolve);
97
95
  }
98
- const defaults = [];
96
+ var defaults = [];
99
97
  function resolveDefault(schema) {
100
- for (let index = defaults.length - 1; index >= 0; index--) {
101
- const resolver = defaults[index];
102
- const res = resolver(schema);
103
- if (res) return res;
104
- }
98
+ for (let index = defaults.length - 1; index >= 0; index--) {
99
+ const resolver = defaults[index];
100
+ const res = resolver(schema);
101
+ if (res) return res;
102
+ }
105
103
  }
106
104
  registerDefault((schema) => {
107
- if (schema instanceof z.ZodArray) {
108
- const elOptions = resolveCodecOptions(
109
- // FIXME: why is this cast needed ?
110
- schema.def.element
111
- );
112
- return normalizeCodecOptions(schema, {
113
- decode(ctx) {
114
- const { xml } = ctx;
115
- if (!xml) return [];
116
- return xml.elements.filter((el) => el.type === "element").map((el) => elOptions.decode({ options: elOptions, xml: el }));
117
- },
118
- // FIXME: when encode method was missing typescript didn't complain
119
- encode(ctx) {
120
- const values = ctx.data;
121
- if (!Array.isArray(values)) throw new Error("expected array");
122
- return {
123
- type: "element",
124
- name: ctx.options.tagname(ctx),
125
- attributes: {},
126
- elements: values.map((v) => elOptions.encode({ options: elOptions, data: v }))
127
- };
128
- }
129
- });
130
- }
131
- if (schema instanceof z.ZodOptional) {
132
- const inner = schema.def.innerType;
133
- if (!isZodType(inner)) throw new Error(`Expected a ZodType, got ${inner}`);
134
- const innerOptions = resolveCodecOptions(inner);
135
- return normalizeCodecOptions(schema, {
136
- decode(ctx) {
137
- if (!ctx.xml) return void 0;
138
- else return innerOptions.decode(ctx);
139
- },
140
- encode(ctx) {
141
- if (typeof ctx.data === "undefined")
142
- return {};
143
- else return innerOptions.encode(ctx);
144
- }
145
- });
146
- }
147
- if (schema instanceof z.ZodDefault) {
148
- const { innerType: inner, defaultValue } = schema.def;
149
- if (!isZodType(inner)) throw new Error(`Expected a ZodType, got ${inner}`);
150
- const innerOptions = resolveCodecOptions(inner);
151
- const getDefault = typeof schema.def.defaultValue === "function" ? schema.def.defaultValue : () => defaultValue;
152
- return normalizeCodecOptions(schema, {
153
- decode(ctx) {
154
- if (!ctx.xml) return getDefault();
155
- else return innerOptions.decode(ctx);
156
- },
157
- encode(ctx) {
158
- return innerOptions.encode(ctx);
159
- }
160
- });
161
- }
162
- if (schema instanceof z.ZodLazy) {
163
- const inner = schema.def.getter();
164
- if (!isZodType(inner)) throw new Error(`Expected a ZodType, got ${inner}`);
165
- return resolveDefault(inner);
166
- }
167
- if (schema instanceof z.ZodCodec) {
168
- const inSchema = schema.def.in;
169
- const outSchema = schema.def.out;
170
- if (!isZodType(inSchema))
171
- throw new Error(`Expected schema.def.in to be a ZodType, got ${inSchema}`);
172
- if (!isZodType(outSchema))
173
- throw new Error(`Expected schema.def.out to be a ZodType, got ${outSchema}`);
174
- const inputCodecOptions = resolveCodecOptions(inSchema);
175
- return normalizeCodecOptions(schema, {
176
- decode({ xml }) {
177
- const input = inputCodecOptions.decode({ options: inputCodecOptions, xml });
178
- return schema.def.transform(input, { value: input, issues: [] });
179
- },
180
- encode(ctx) {
181
- const data = outSchema.encode(ctx.data);
182
- const innerOpts = ctx.options.tagname !== inputCodecOptions.tagname ? { ...inputCodecOptions, tagname: ctx.options.tagname } : inputCodecOptions;
183
- return innerOpts.encode({ options: innerOpts, data });
184
- }
185
- });
186
- }
187
- if (schema instanceof z.ZodLiteral) {
188
- const values = schema.def.values;
189
- const valuesFromString = Object.fromEntries(values.map((v) => [v.toString(), v]));
190
- return normalizeCodecOptions(schema, {
191
- decode(ctx) {
192
- const raw = XML.getContent(ctx.xml);
193
- if (!(raw in valuesFromString))
194
- throw new Error(`Could not retrieve literal value from string "${raw}"`);
195
- return valuesFromString[raw];
196
- },
197
- encode(ctx) {
198
- return XML.fromContent(String(ctx.data), ctx.options.tagname(ctx));
199
- }
200
- });
201
- }
202
- if (schema instanceof z.ZodString) {
203
- return normalizeCodecOptions(schema, {
204
- decode(ctx) {
205
- return XML.getContent(ctx.xml);
206
- },
207
- encode(ctx) {
208
- return XML.fromContent(ctx.data, ctx.options.tagname(ctx));
209
- }
210
- });
211
- }
212
- if (schema instanceof z.ZodNumber) {
213
- return normalizeCodecOptions(schema, {
214
- decode(ctx) {
215
- return Number(XML.getContent(ctx.xml));
216
- },
217
- encode(ctx) {
218
- return XML.fromContent(ctx.data.toString(), ctx.options.tagname(ctx));
219
- }
220
- });
221
- }
222
- if (schema instanceof z.ZodBoolean) {
223
- return normalizeCodecOptions(schema, {
224
- decode(ctx) {
225
- return XML.getContent(ctx.xml) === "true";
226
- },
227
- encode(ctx) {
228
- return XML.fromContent(ctx.data.toString(), ctx.options.tagname(ctx));
229
- }
230
- });
231
- }
105
+ if (schema instanceof z.ZodArray) {
106
+ const elOptions = resolveCodecOptions(schema.def.element);
107
+ return normalizeCodecOptions(schema, {
108
+ decode(ctx) {
109
+ const { xml } = ctx;
110
+ if (!xml) return [];
111
+ return xml.elements.filter((el) => el.type === "element").map((el) => elOptions.decode({
112
+ options: elOptions,
113
+ xml: el
114
+ }));
115
+ },
116
+ encode(ctx) {
117
+ const values = ctx.data;
118
+ if (!Array.isArray(values)) throw new Error("expected array");
119
+ return {
120
+ type: "element",
121
+ name: ctx.options.tagname(ctx),
122
+ attributes: {},
123
+ elements: values.map((v) => elOptions.encode({
124
+ options: elOptions,
125
+ data: v
126
+ }))
127
+ };
128
+ }
129
+ });
130
+ }
131
+ if (schema instanceof z.ZodOptional) {
132
+ const inner = schema.def.innerType;
133
+ if (!isZodType(inner)) throw new Error(`Expected a ZodType, got ${inner}`);
134
+ const innerOptions = resolveCodecOptions(inner);
135
+ return normalizeCodecOptions(schema, {
136
+ decode(ctx) {
137
+ if (!ctx.xml) return void 0;
138
+ else return innerOptions.decode(ctx);
139
+ },
140
+ encode(ctx) {
141
+ if (typeof ctx.data === "undefined") return {};
142
+ else return innerOptions.encode(ctx);
143
+ }
144
+ });
145
+ }
146
+ if (schema instanceof z.ZodDefault) {
147
+ const { innerType: inner, defaultValue } = schema.def;
148
+ if (!isZodType(inner)) throw new Error(`Expected a ZodType, got ${inner}`);
149
+ const innerOptions = resolveCodecOptions(inner);
150
+ const getDefault = typeof schema.def.defaultValue === "function" ? schema.def.defaultValue : () => defaultValue;
151
+ return normalizeCodecOptions(schema, {
152
+ decode(ctx) {
153
+ if (!ctx.xml) return getDefault();
154
+ else return innerOptions.decode(ctx);
155
+ },
156
+ encode(ctx) {
157
+ return innerOptions.encode(ctx);
158
+ }
159
+ });
160
+ }
161
+ if (schema instanceof z.ZodLazy) {
162
+ const inner = schema.def.getter();
163
+ if (!isZodType(inner)) throw new Error(`Expected a ZodType, got ${inner}`);
164
+ return resolveDefault(inner);
165
+ }
166
+ if (schema instanceof z.ZodCodec) {
167
+ const inSchema = schema.def.in;
168
+ const outSchema = schema.def.out;
169
+ if (!isZodType(inSchema)) throw new Error(`Expected schema.def.in to be a ZodType, got ${inSchema}`);
170
+ if (!isZodType(outSchema)) throw new Error(`Expected schema.def.out to be a ZodType, got ${outSchema}`);
171
+ const inputCodecOptions = resolveCodecOptions(inSchema);
172
+ return normalizeCodecOptions(schema, {
173
+ decode({ xml }) {
174
+ const input = inputCodecOptions.decode({
175
+ options: inputCodecOptions,
176
+ xml
177
+ });
178
+ return schema.def.transform(input, {
179
+ value: input,
180
+ issues: []
181
+ });
182
+ },
183
+ encode(ctx) {
184
+ const data = outSchema.encode(ctx.data);
185
+ const innerOpts = ctx.options.tagname !== inputCodecOptions.tagname ? {
186
+ ...inputCodecOptions,
187
+ tagname: ctx.options.tagname
188
+ } : inputCodecOptions;
189
+ return innerOpts.encode({
190
+ options: innerOpts,
191
+ data
192
+ });
193
+ }
194
+ });
195
+ }
196
+ if (schema instanceof z.ZodLiteral) {
197
+ const values = schema.def.values;
198
+ const valuesFromString = Object.fromEntries(values.map((v) => [v.toString(), v]));
199
+ return normalizeCodecOptions(schema, {
200
+ decode(ctx) {
201
+ const raw = XML.getContent(ctx.xml);
202
+ if (!(raw in valuesFromString)) throw new Error(`Could not retrieve literal value from string "${raw}"`);
203
+ return valuesFromString[raw];
204
+ },
205
+ encode(ctx) {
206
+ return XML.fromContent(String(ctx.data), ctx.options.tagname(ctx));
207
+ }
208
+ });
209
+ }
210
+ if (schema instanceof z.ZodString) return normalizeCodecOptions(schema, {
211
+ decode(ctx) {
212
+ return XML.getContent(ctx.xml);
213
+ },
214
+ encode(ctx) {
215
+ return XML.fromContent(ctx.data, ctx.options.tagname(ctx));
216
+ }
217
+ });
218
+ if (schema instanceof z.ZodNumber) return normalizeCodecOptions(schema, {
219
+ decode(ctx) {
220
+ return Number(XML.getContent(ctx.xml));
221
+ },
222
+ encode(ctx) {
223
+ return XML.fromContent(ctx.data.toString(), ctx.options.tagname(ctx));
224
+ }
225
+ });
226
+ if (schema instanceof z.ZodBoolean) return normalizeCodecOptions(schema, {
227
+ decode(ctx) {
228
+ return XML.getContent(ctx.xml) === "true";
229
+ },
230
+ encode(ctx) {
231
+ return XML.fromContent(ctx.data.toString(), ctx.options.tagname(ctx));
232
+ }
233
+ });
232
234
  });
233
235
  registerDefault((schema) => {
234
- if (schema instanceof z.ZodObject) {
235
- const options = resolvePropertiesCodecOptions(schema);
236
- return normalizeCodecOptions(schema, {
237
- decode(ctx) {
238
- const sequence = [];
239
- const propContexts = Object.fromEntries(
240
- Object.entries(options).map(([name, propOpts]) => {
241
- const tagname = propOpts.propertyTagname({ name, options: propOpts });
242
- return [
243
- name,
244
- {
245
- name,
246
- options: propOpts,
247
- tagname,
248
- // starts as a collection container; replaced with actual element or null after matching
249
- xml: { elements: [] }
250
- }
251
- ];
252
- })
253
- );
254
- const seenProperties = /* @__PURE__ */ new Set();
255
- for (const el of ctx.xml.elements) {
256
- if (el.type !== "element") continue;
257
- const matches = [];
258
- for (const prop in options) {
259
- const propCtx = propContexts[prop];
260
- if (options[prop].propertyMatch(el, propCtx)) {
261
- matches.push(prop);
262
- propCtx.xml.elements.push(el);
263
- }
264
- }
265
- if (!matches.length) {
266
- sequence.push(el);
267
- continue;
268
- } else if (matches.length === 1) {
269
- const propName = matches[0];
270
- if (seenProperties.has(propName)) {
271
- const prop = options[propName];
272
- if (!prop.inlineProperty)
273
- throw new Error(
274
- "Matching multiple elements for a single property is only supported when `inlineProperty` is true"
275
- );
276
- } else {
277
- sequence.push(propName);
278
- seenProperties.add(propName);
279
- }
280
- } else {
281
- throw new Error(
282
- `Same element was matched by multiple properties: ${matches.join(", ")}`
283
- );
284
- }
285
- }
286
- for (const propName in options) {
287
- if (!seenProperties.has(propName)) sequence.push(propName);
288
- }
289
- const result = {};
290
- for (const prop in options) {
291
- const o = options[prop];
292
- const propCtx = propContexts[prop];
293
- if (!o.inlineProperty) {
294
- const matches = propCtx.xml.elements;
295
- if (matches.length === 0) propCtx.xml = null;
296
- else {
297
- assertSingleElement(matches);
298
- propCtx.xml = matches[0];
299
- }
300
- }
301
- o.decodeAsProperty({
302
- // @ts-ignore
303
- options: ctx.options,
304
- xml: ctx.xml,
305
- // @ts-ignore
306
- property: propCtx,
307
- result
308
- });
309
- }
310
- Object.defineProperty(result, XML_STATE, {
311
- value: { fieldOrder: sequence },
312
- enumerable: false,
313
- writable: true,
314
- configurable: true
315
- });
316
- return result;
317
- },
318
- encode(ctx) {
319
- const { data } = ctx;
320
- const result = {
321
- type: "element",
322
- name: ctx.options.tagname(ctx),
323
- // already create the attributes record so `attr(...)` encoding handlers don't have to
324
- attributes: {},
325
- elements: []
326
- };
327
- const sequence = data[XML_STATE]?.fieldOrder ?? Object.keys(options);
328
- for (const item of sequence) {
329
- if (typeof item === "string") {
330
- const o = options[item];
331
- if (!o) {
332
- throw new Error(`Failed to resolve property options for sequence item ${item}`);
333
- }
334
- o.encodeAsProperty({
335
- // FIXME should not need type casts
336
- options: ctx.options,
337
- data,
338
- property: {
339
- name: item,
340
- options: o,
341
- tagname: o.propertyTagname({ name: item, options: o }),
342
- value: data[item]
343
- },
344
- result
345
- });
346
- } else {
347
- result.elements.push(item);
348
- }
349
- }
350
- return result;
351
- }
352
- });
353
- }
236
+ if (schema instanceof z.ZodObject) {
237
+ const options = resolvePropertiesCodecOptions(schema);
238
+ return normalizeCodecOptions(schema, {
239
+ decode(ctx) {
240
+ const sequence = [];
241
+ const propContexts = Object.fromEntries(Object.entries(options).map(([name, propOpts]) => {
242
+ return [name, {
243
+ name,
244
+ options: propOpts,
245
+ tagname: propOpts.propertyTagname({
246
+ name,
247
+ options: propOpts
248
+ }),
249
+ xml: { elements: [] }
250
+ }];
251
+ }));
252
+ const seenProperties = /* @__PURE__ */ new Set();
253
+ for (const el of ctx.xml.elements) {
254
+ if (el.type !== "element") continue;
255
+ const matches = [];
256
+ for (const prop in options) {
257
+ const propCtx = propContexts[prop];
258
+ if (options[prop].propertyMatch(el, propCtx)) {
259
+ matches.push(prop);
260
+ propCtx.xml.elements.push(el);
261
+ }
262
+ }
263
+ if (!matches.length) {
264
+ sequence.push(el);
265
+ continue;
266
+ } else if (matches.length === 1) {
267
+ const propName = matches[0];
268
+ if (seenProperties.has(propName)) {
269
+ if (!options[propName].inlineProperty) throw new Error("Matching multiple elements for a single property is only supported when `inlineProperty` is true");
270
+ } else {
271
+ sequence.push(propName);
272
+ seenProperties.add(propName);
273
+ }
274
+ } else throw new Error(`Same element was matched by multiple properties: ${matches.join(", ")}`);
275
+ }
276
+ for (const propName in options) if (!seenProperties.has(propName)) sequence.push(propName);
277
+ const result = {};
278
+ for (const prop in options) {
279
+ const o = options[prop];
280
+ const propCtx = propContexts[prop];
281
+ if (!o.inlineProperty) {
282
+ const matches = propCtx.xml.elements;
283
+ if (matches.length === 0) propCtx.xml = null;
284
+ else {
285
+ assertSingleElement(matches);
286
+ propCtx.xml = matches[0];
287
+ }
288
+ }
289
+ o.decodeAsProperty({
290
+ options: ctx.options,
291
+ xml: ctx.xml,
292
+ property: propCtx,
293
+ result
294
+ });
295
+ }
296
+ Object.defineProperty(result, XML_STATE, {
297
+ value: { fieldOrder: sequence },
298
+ enumerable: false,
299
+ writable: true,
300
+ configurable: true
301
+ });
302
+ return result;
303
+ },
304
+ encode(ctx) {
305
+ const { data } = ctx;
306
+ const result = {
307
+ type: "element",
308
+ name: ctx.options.tagname(ctx),
309
+ attributes: {},
310
+ elements: []
311
+ };
312
+ const sequence = data[XML_STATE]?.fieldOrder ?? Object.keys(options);
313
+ for (const item of sequence) if (typeof item === "string") {
314
+ const o = options[item];
315
+ if (!o) throw new Error(`Failed to resolve property options for sequence item ${item}`);
316
+ o.encodeAsProperty({
317
+ options: ctx.options,
318
+ data,
319
+ property: {
320
+ name: item,
321
+ options: o,
322
+ tagname: o.propertyTagname({
323
+ name: item,
324
+ options: o
325
+ }),
326
+ value: data[item]
327
+ },
328
+ result
329
+ });
330
+ } else result.elements.push(item);
331
+ return result;
332
+ }
333
+ });
334
+ }
354
335
  });
355
- function xmlCodec(schema) {
356
- const codec = z.codec(z.string(), schema, {
357
- decode(xml) {
358
- const xmlRoot = XML.parse(xml);
359
- const xmlEl = XML.elementFromRoot(xmlRoot);
360
- const input = decode(schema, xmlEl);
361
- return input;
362
- },
363
- encode(value) {
364
- const xmlEl = encode(
365
- schema,
366
- // FIXME: value is expected to be of type input<S>
367
- // so `schema` should be able or re-encoding its output
368
- value
369
- );
370
- return XML.stringify({ elements: [xmlEl] });
371
- }
372
- });
373
- return codec;
374
- }
375
- export {
376
- XML_STATE,
377
- assertSingleElement,
378
- assertSingleRoot,
379
- decode,
380
- encode,
381
- normalizeCodecOptions,
382
- registerDefault,
383
- xmlCodec
384
- };
385
- //# sourceMappingURL=codec.js.map
336
+ //#endregion
337
+ export { XML_STATE, decode, encode, normalizeCodecOptions, registerDefault };
338
+
339
+ //# sourceMappingURL=codec.js.map