xml-model 1.3.2 → 2.0.0-beta.1
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/README.md +39 -35
- package/dist/index.d.ts +3 -7
- package/dist/index.js +18 -17
- package/dist/model.d.ts +53 -0
- package/dist/model.js +69 -0
- package/dist/util/zod.d.ts +4 -0
- package/dist/util/zod.js +21 -0
- package/dist/xml/codec.d.ts +87 -0
- package/dist/xml/codec.js +385 -0
- package/dist/xml/examples.d.ts +188 -0
- package/dist/xml/index.d.ts +5 -32
- package/dist/xml/index.js +14 -54
- package/dist/xml/model.d.ts +18 -0
- package/dist/xml/model.js +37 -0
- package/dist/xml/schema-meta.d.ts +57 -0
- package/dist/xml/schema-meta.js +96 -0
- package/dist/xml/xml-js.d.ts +138 -3
- package/dist/xml/xml-js.js +89 -5
- package/package.json +10 -23
- package/dist/_virtual/Reflect.js +0 -8
- package/dist/_virtual/Reflect2.js +0 -5
- package/dist/_virtual/_commonjsHelpers.js +0 -47
- package/dist/defaults.d.ts +0 -15
- package/dist/defaults.js +0 -130
- package/dist/errors.d.ts +0 -24
- package/dist/errors.js +0 -45
- package/dist/middleware.d.ts +0 -10
- package/dist/middleware.js +0 -25
- package/dist/model/built-ins.d.ts +0 -3
- package/dist/model/built-ins.js +0 -43
- package/dist/model/index.d.ts +0 -21
- package/dist/model/index.js +0 -236
- package/dist/model/property.d.ts +0 -6
- package/dist/model/property.js +0 -67
- package/dist/model/registry.d.ts +0 -9
- package/dist/model/registry.js +0 -19
- package/dist/model/types.d.ts +0 -74
- package/dist/node_modules/reflect-metadata/Reflect.js +0 -806
- package/dist/types.d.ts +0 -17
- package/dist/util/is-regexp.d.ts +0 -12
- package/dist/util/is-regexp.js +0 -8
- package/dist/util/merge-maps.d.ts +0 -2
- package/dist/util/merge-maps.js +0 -23
- package/dist/vite/index.d.ts +0 -53
- package/dist/vite/index.js +0 -63
- package/dist/vite/node_modules/typescript-rtti/dist.esm/common/format.js +0 -105
- package/dist/vite/node_modules/typescript-rtti/dist.esm/common/index.js +0 -55
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/api-call-transformer.js +0 -152
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/common/class-analyzer.js +0 -83
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/common/compile-error.js +0 -8
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/common/import-analyzer.js +0 -89
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/common/interface-analyzer.js +0 -58
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/common/visitor-base.js +0 -93
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/declarations-emitter.js +0 -31
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/encode-parameter.js +0 -64
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/find-relative-path.js +0 -41
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/flags.js +0 -43
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/forward-ref.js +0 -20
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/get-exports-for-symbol.js +0 -64
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/index.js +0 -130
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/legacy-decorator.js +0 -10
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/legacy-type-encoder.js +0 -82
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/literal-node.js +0 -9
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/metadata-collector.js +0 -56
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/metadata-decorator.js +0 -80
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/metadata-emitter.js +0 -425
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/metadata-encoder.js +0 -212
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/rt-helper.js +0 -96
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/rtti-visitor-base.js +0 -28
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/serialize.js +0 -31
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/type-encoder.js +0 -76
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/type-literal.js +0 -499
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/utils.js +0 -906
- package/dist/vite/node_modules/typescript-rtti/dist.esm/transformer/workarounds.js +0 -7
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { XML } from "./xml-js.js";
|
|
3
|
+
import { getUserOptions } from "./schema-meta.js";
|
|
4
|
+
import { kebabCase } from "../util/kebab-case.js";
|
|
5
|
+
import { isZodType } from "../util/zod.js";
|
|
6
|
+
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`);
|
|
12
|
+
}
|
|
13
|
+
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;
|
|
68
|
+
}
|
|
69
|
+
const cache = /* @__PURE__ */ new Map();
|
|
70
|
+
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;
|
|
77
|
+
}
|
|
78
|
+
const XML_STATE = /* @__PURE__ */ Symbol("xml-model.state");
|
|
79
|
+
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;
|
|
86
|
+
}
|
|
87
|
+
function decode(schema, xml) {
|
|
88
|
+
const options = resolveCodecOptions(schema);
|
|
89
|
+
return options.decode({ options, xml });
|
|
90
|
+
}
|
|
91
|
+
function encode(schema, data) {
|
|
92
|
+
const options = resolveCodecOptions(schema);
|
|
93
|
+
return options.encode({ options, data });
|
|
94
|
+
}
|
|
95
|
+
function registerDefault(resolve) {
|
|
96
|
+
defaults.push(resolve);
|
|
97
|
+
}
|
|
98
|
+
const defaults = [];
|
|
99
|
+
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
|
+
}
|
|
105
|
+
}
|
|
106
|
+
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
|
+
}
|
|
232
|
+
});
|
|
233
|
+
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
|
+
}
|
|
354
|
+
});
|
|
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
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
declare const Engine_base: import('./model').XmlModelConstructor<z.ZodObject<{
|
|
3
|
+
type: z.ZodString;
|
|
4
|
+
horsepower: z.ZodNumber;
|
|
5
|
+
}, z.core.$strip>, {
|
|
6
|
+
type: string;
|
|
7
|
+
horsepower: number;
|
|
8
|
+
}>;
|
|
9
|
+
/**
|
|
10
|
+
* A car engine. Demonstrates a basic nested class with one XML attribute
|
|
11
|
+
* (`type`) and one child element (`horsepower`).
|
|
12
|
+
*/
|
|
13
|
+
export declare class Engine extends Engine_base {
|
|
14
|
+
}
|
|
15
|
+
declare const Vehicle_base: import('./model').XmlModelConstructor<z.ZodObject<{
|
|
16
|
+
vin: z.ZodString;
|
|
17
|
+
make: z.ZodString;
|
|
18
|
+
year: z.ZodNumber;
|
|
19
|
+
}, z.core.$strip>, {
|
|
20
|
+
vin: string;
|
|
21
|
+
make: string;
|
|
22
|
+
year: number;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Base vehicle class. Demonstrates `xml.attr()` for identifier fields and
|
|
26
|
+
* `xml.prop()` for child-element fields. Custom methods on the class are
|
|
27
|
+
* available on every parsed instance.
|
|
28
|
+
*/
|
|
29
|
+
export declare class Vehicle extends Vehicle_base {
|
|
30
|
+
/** Returns a human-readable label for this vehicle. */
|
|
31
|
+
label(): string;
|
|
32
|
+
}
|
|
33
|
+
declare const Car_base: Omit<typeof Vehicle, keyof import('..').ModelConstructor<S, Inst>> & import('..').ModelConstructor<z.ZodObject<{
|
|
34
|
+
vin: z.ZodString;
|
|
35
|
+
make: z.ZodString;
|
|
36
|
+
year: z.ZodNumber;
|
|
37
|
+
doors: z.ZodNumber;
|
|
38
|
+
engine: z.ZodCodec<z.ZodObject<{
|
|
39
|
+
type: z.ZodString;
|
|
40
|
+
horsepower: z.ZodNumber;
|
|
41
|
+
}, z.core.$strip>, z.ZodCustom<Engine, Engine>>;
|
|
42
|
+
}, z.core.$strip>, Vehicle & {
|
|
43
|
+
vin: string;
|
|
44
|
+
make: string;
|
|
45
|
+
year: number;
|
|
46
|
+
doors: number;
|
|
47
|
+
engine?: Engine;
|
|
48
|
+
}>;
|
|
49
|
+
/**
|
|
50
|
+
* Car extends Vehicle using `Vehicle.extend()`, which creates a **true subclass**:
|
|
51
|
+
* instances are `instanceof Vehicle` and inherit Vehicle's methods (e.g. `label()`).
|
|
52
|
+
*
|
|
53
|
+
* Demonstrates:
|
|
54
|
+
* - chaining `.extend()` to add fields to a parent model
|
|
55
|
+
* - `xml.prop(Engine)` to embed a nested xmlModel class as a child element
|
|
56
|
+
*/
|
|
57
|
+
export declare class Car extends Car_base {
|
|
58
|
+
}
|
|
59
|
+
declare const SportCar_base: Omit<typeof Car, keyof import('..').ModelConstructor<S, Inst>> & import('..').ModelConstructor<z.ZodObject<{
|
|
60
|
+
vin: z.ZodString;
|
|
61
|
+
make: z.ZodString;
|
|
62
|
+
year: z.ZodNumber;
|
|
63
|
+
doors: z.ZodNumber;
|
|
64
|
+
engine: z.ZodCodec<z.ZodObject<{
|
|
65
|
+
type: z.ZodString;
|
|
66
|
+
horsepower: z.ZodNumber;
|
|
67
|
+
}, z.core.$strip>, z.ZodCustom<Engine, Engine>>;
|
|
68
|
+
topSpeed: z.ZodNumber;
|
|
69
|
+
}, z.core.$strip>, Car & {
|
|
70
|
+
vin: string;
|
|
71
|
+
make: string;
|
|
72
|
+
year: number;
|
|
73
|
+
doors: number;
|
|
74
|
+
topSpeed: number;
|
|
75
|
+
engine?: Engine;
|
|
76
|
+
}>;
|
|
77
|
+
/**
|
|
78
|
+
* SportCar shows that `.extend()` chains across multiple levels.
|
|
79
|
+
* Instances are `instanceof SportCar`, `instanceof Car`, and `instanceof Vehicle`.
|
|
80
|
+
*/
|
|
81
|
+
export declare class SportCar extends SportCar_base {
|
|
82
|
+
}
|
|
83
|
+
declare const Motorcycle_base: Omit<typeof Vehicle, keyof import('..').ModelConstructor<S, Inst>> & import('..').ModelConstructor<z.ZodObject<{
|
|
84
|
+
vin: z.ZodString;
|
|
85
|
+
make: z.ZodString;
|
|
86
|
+
year: z.ZodNumber;
|
|
87
|
+
sidecar: z.ZodOptional<z.ZodBoolean>;
|
|
88
|
+
}, z.core.$strip>, Vehicle & {
|
|
89
|
+
vin: string;
|
|
90
|
+
make: string;
|
|
91
|
+
year: number;
|
|
92
|
+
sidecar?: boolean;
|
|
93
|
+
}>;
|
|
94
|
+
/**
|
|
95
|
+
* Motorcycle extends Vehicle with an optional boolean field.
|
|
96
|
+
* When `<sidecar>` is absent from the XML the field is `undefined`;
|
|
97
|
+
* `toXMLString` omits it entirely.
|
|
98
|
+
*/
|
|
99
|
+
export declare class Motorcycle extends Motorcycle_base {
|
|
100
|
+
}
|
|
101
|
+
declare const Fleet_base: import('./model').XmlModelConstructor<z.ZodObject<{
|
|
102
|
+
name: z.ZodString;
|
|
103
|
+
cars: z.ZodArray<z.ZodCodec<z.ZodObject<{
|
|
104
|
+
vin: z.ZodString;
|
|
105
|
+
make: z.ZodString;
|
|
106
|
+
year: z.ZodNumber;
|
|
107
|
+
doors: z.ZodNumber;
|
|
108
|
+
engine: z.ZodCodec<z.ZodObject<{
|
|
109
|
+
type: z.ZodString;
|
|
110
|
+
horsepower: z.ZodNumber;
|
|
111
|
+
}, z.core.$strip>, z.ZodCustom<Engine, Engine>>;
|
|
112
|
+
}, z.core.$strip>, z.ZodCustom<Car, Car>>>;
|
|
113
|
+
motorcycles: z.ZodArray<z.ZodCodec<z.ZodObject<{
|
|
114
|
+
vin: z.ZodString;
|
|
115
|
+
make: z.ZodString;
|
|
116
|
+
year: z.ZodNumber;
|
|
117
|
+
sidecar: z.ZodOptional<z.ZodBoolean>;
|
|
118
|
+
}, z.core.$strip>, z.ZodCustom<Motorcycle, Motorcycle>>>;
|
|
119
|
+
}, z.core.$strip>, {
|
|
120
|
+
name: string;
|
|
121
|
+
cars: Car[];
|
|
122
|
+
motorcycles: Motorcycle[];
|
|
123
|
+
}>;
|
|
124
|
+
/**
|
|
125
|
+
* Fleet demonstrates **inline arrays** of multiple vehicle types.
|
|
126
|
+
* `inline: true` places each item as a direct sibling element inside the
|
|
127
|
+
* root tag rather than wrapping them in a container element.
|
|
128
|
+
*/
|
|
129
|
+
export declare class Fleet extends Fleet_base {
|
|
130
|
+
/** Total number of vehicles across all types in this fleet. */
|
|
131
|
+
totalVehicles(): number;
|
|
132
|
+
}
|
|
133
|
+
declare const Showroom_base: import('./model').XmlModelConstructor<z.ZodObject<{
|
|
134
|
+
name: z.ZodString;
|
|
135
|
+
models: z.ZodArray<z.ZodString>;
|
|
136
|
+
}, z.core.$strip>, {
|
|
137
|
+
name: string;
|
|
138
|
+
models: string[];
|
|
139
|
+
}>;
|
|
140
|
+
/**
|
|
141
|
+
* A showroom holds an inventory of car model names.
|
|
142
|
+
* Demonstrates a **non-inline** (wrapped) array: all items are nested inside
|
|
143
|
+
* a single `<models>` container element, as opposed to being direct siblings
|
|
144
|
+
* of the root element.
|
|
145
|
+
*
|
|
146
|
+
* ```xml
|
|
147
|
+
* <showroom name="Acme Dealers">
|
|
148
|
+
* <models>
|
|
149
|
+
* <model>Corolla</model>
|
|
150
|
+
* <model>Civic</model>
|
|
151
|
+
* </models>
|
|
152
|
+
* </showroom>
|
|
153
|
+
* ```
|
|
154
|
+
*
|
|
155
|
+
* Contrast with `Fleet`, which uses `inline: true` so each `<car>` / `<motorcycle>`
|
|
156
|
+
* is a direct child of `<fleet>` with no container wrapper.
|
|
157
|
+
*/
|
|
158
|
+
export declare class Showroom extends Showroom_base {
|
|
159
|
+
}
|
|
160
|
+
declare const CarStandalone_base: import('./model').XmlModelConstructor<z.ZodObject<{
|
|
161
|
+
vin: z.ZodString;
|
|
162
|
+
make: z.ZodString;
|
|
163
|
+
year: z.ZodNumber;
|
|
164
|
+
doors: z.ZodNumber;
|
|
165
|
+
engine: z.ZodCodec<z.ZodObject<{
|
|
166
|
+
type: z.ZodString;
|
|
167
|
+
horsepower: z.ZodNumber;
|
|
168
|
+
}, z.core.$strip>, z.ZodCustom<Engine, Engine>>;
|
|
169
|
+
}, z.core.$strip>, {
|
|
170
|
+
vin: string;
|
|
171
|
+
make: string;
|
|
172
|
+
year: number;
|
|
173
|
+
doors: number;
|
|
174
|
+
engine?: Engine;
|
|
175
|
+
}>;
|
|
176
|
+
/**
|
|
177
|
+
* Demonstrates the alternative to `.extend()`: passing a manually extended
|
|
178
|
+
* schema to `xmlModel()`. This produces a **fresh class** with no prototype
|
|
179
|
+
* link to `Vehicle` — instances are **not** `instanceof Vehicle` and Vehicle's
|
|
180
|
+
* methods are unavailable.
|
|
181
|
+
*
|
|
182
|
+
* Use this pattern when you want a standalone class that reuses a schema shape
|
|
183
|
+
* but does not need to be part of the parent class hierarchy.
|
|
184
|
+
*/
|
|
185
|
+
export declare class CarStandalone extends CarStandalone_base {
|
|
186
|
+
}
|
|
187
|
+
export {};
|
|
188
|
+
//# sourceMappingURL=examples.d.ts.map
|
package/dist/xml/index.d.ts
CHANGED
|
@@ -1,33 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export
|
|
6
|
-
elements: [{
|
|
7
|
-
type: "text";
|
|
8
|
-
text: string;
|
|
9
|
-
}] | [];
|
|
10
|
-
};
|
|
11
|
-
export declare function fromContent(content: string, tag: string, attributes?: XMLElement["attributes"]): {
|
|
12
|
-
type: "element";
|
|
13
|
-
name: string;
|
|
14
|
-
attributes?: XMLElement["attributes"];
|
|
15
|
-
elements: [{
|
|
16
|
-
type: "text";
|
|
17
|
-
text: string;
|
|
18
|
-
}] | [];
|
|
19
|
-
};
|
|
20
|
-
export declare function addElement(xml: XMLElement, element: XMLElement): void;
|
|
21
|
-
export declare function setAttribute(xml: XMLElement, attribute: string, value: string): void;
|
|
22
|
-
export declare function deleteAttribute(xml: XMLElement, attribute: string): void;
|
|
23
|
-
declare const XML: {
|
|
24
|
-
parse: typeof parse;
|
|
25
|
-
stringify: typeof import('xml-js').js2xml;
|
|
26
|
-
fromContent: typeof fromContent;
|
|
27
|
-
getContent: typeof getContent;
|
|
28
|
-
addElement: typeof addElement;
|
|
29
|
-
setAttribute: typeof setAttribute;
|
|
30
|
-
deleteAttribute: typeof deleteAttribute;
|
|
31
|
-
};
|
|
32
|
-
export default XML;
|
|
1
|
+
export * from './xml-js';
|
|
2
|
+
export { xml } from './schema-meta';
|
|
3
|
+
export type { UserCodecOptions } from './codec';
|
|
4
|
+
export { registerDefault, normalizeCodecOptions } from './codec';
|
|
5
|
+
export { xmlModel, type XmlModelConstructor } from './model';
|
|
33
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/xml/index.js
CHANGED
|
@@ -1,57 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
5
|
-
const stringify = XMLJS.stringify;
|
|
6
|
-
function getContent(xml) {
|
|
7
|
-
if (xml.elements?.length === 1) {
|
|
8
|
-
const content = xml.elements[0];
|
|
9
|
-
if (content.type === "text") return content.text;
|
|
10
|
-
}
|
|
11
|
-
if (!xml.elements) return "";
|
|
12
|
-
throw new TypeError(`can't get text from XMLElement: ${JSON.stringify(xml)}`);
|
|
13
|
-
}
|
|
14
|
-
function fromContent(content = "", tag, attributes) {
|
|
15
|
-
const el = {
|
|
16
|
-
elements: content ? [{ type: "text", text: String(content) }] : []
|
|
17
|
-
};
|
|
18
|
-
if (tag) el.name = tag;
|
|
19
|
-
if (attributes) {
|
|
20
|
-
if (!el.name) throw new TypeError("please provide a name if you want to provide attributes");
|
|
21
|
-
el.attributes = attributes;
|
|
22
|
-
}
|
|
23
|
-
if (el.name) el.type = "element";
|
|
24
|
-
return el;
|
|
25
|
-
}
|
|
26
|
-
function addElement(xml, element) {
|
|
27
|
-
if (!xml.elements) xml.elements = [];
|
|
28
|
-
xml.elements.push(element);
|
|
29
|
-
}
|
|
30
|
-
function setAttribute(xml, attribute, value) {
|
|
31
|
-
if (!xml.attributes) xml.attributes = {};
|
|
32
|
-
xml.attributes[attribute] = value;
|
|
33
|
-
}
|
|
34
|
-
function deleteAttribute(xml, attribute) {
|
|
35
|
-
if (!xml.attributes) return;
|
|
36
|
-
delete xml.attributes[attribute];
|
|
37
|
-
}
|
|
38
|
-
const XML = {
|
|
39
|
-
parse,
|
|
40
|
-
stringify,
|
|
41
|
-
fromContent,
|
|
42
|
-
getContent,
|
|
43
|
-
addElement,
|
|
44
|
-
setAttribute,
|
|
45
|
-
deleteAttribute
|
|
46
|
-
};
|
|
1
|
+
import { XML, ZXMLCommentNode, ZXMLElementNode, ZXMLNode, ZXMLRoot, ZXMLTextNode } from "./xml-js.js";
|
|
2
|
+
import { xml } from "./schema-meta.js";
|
|
3
|
+
import { normalizeCodecOptions, registerDefault } from "./codec.js";
|
|
4
|
+
import { xmlModel } from "./model.js";
|
|
47
5
|
export {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
6
|
+
XML,
|
|
7
|
+
ZXMLCommentNode,
|
|
8
|
+
ZXMLElementNode,
|
|
9
|
+
ZXMLNode,
|
|
10
|
+
ZXMLRoot,
|
|
11
|
+
ZXMLTextNode,
|
|
12
|
+
normalizeCodecOptions,
|
|
13
|
+
registerDefault,
|
|
14
|
+
xml,
|
|
15
|
+
xmlModel
|
|
56
16
|
};
|
|
57
17
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { XMLElement, StringifyOptions, XMLRoot } from './xml-js';
|
|
3
|
+
import { ModelConstructor } from '../model';
|
|
4
|
+
import { UserCodecOptions } from './codec';
|
|
5
|
+
/**
|
|
6
|
+
* Constructor type for xmlModel classes.
|
|
7
|
+
* Extends ModelConstructor with XML-specific helpers and a typed extend().
|
|
8
|
+
*/
|
|
9
|
+
export type XmlModelConstructor<S extends z.ZodObject<any> = z.ZodObject<any>, Inst extends z.infer<S> = z.infer<S>> = ModelConstructor<S, Inst> & {
|
|
10
|
+
/** Returns a new instance parsed from an XML string or XMLRoot. */
|
|
11
|
+
fromXML<T extends abstract new (...args: any[]) => any>(this: T, xmlInput: string | XMLRoot | XMLElement): InstanceType<T>;
|
|
12
|
+
/** Converts an instance to an XMLRoot document tree. */
|
|
13
|
+
toXML(instance: z.infer<S>): XMLRoot;
|
|
14
|
+
/** Converts an instance to an XML string. */
|
|
15
|
+
toXMLString(instance: z.infer<S>, options?: StringifyOptions): string;
|
|
16
|
+
};
|
|
17
|
+
export declare function xmlModel<S extends z.ZodObject<any>>(schema: S, options?: UserCodecOptions<S>): XmlModelConstructor<S>;
|
|
18
|
+
//# sourceMappingURL=model.d.ts.map
|