Skip to content

Commit 1635ff5

Browse files
committed
feat: add support xml samples
1 parent 1b6adcb commit 1635ff5

File tree

7 files changed

+603
-3
lines changed

7 files changed

+603
-3
lines changed

package-lock.json

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
},
6868
"dependencies": {
6969
"@types/json-schema": "^7.0.7",
70+
"fast-xml-parser": "^4.5.0",
7071
"json-pointer": "0.6.2"
7172
},
7273
"overrides": {

src/openapi-sampler.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import { traverse, clearCache } from './traverse';
22
import { sampleArray, sampleBoolean, sampleNumber, sampleObject, sampleString } from './samplers/index';
3+
import { XMLBuilder } from 'fast-xml-parser';
4+
5+
const builder = new XMLBuilder({
6+
ignoreAttributes : false,
7+
format: true,
8+
attributeNamePrefix: '$',
9+
textNodeName: '#text',
10+
});
311

412
export var _samplers = {};
513

@@ -11,7 +19,14 @@ const defaults = {
1119
export function sample(schema, options, spec) {
1220
let opts = Object.assign({}, defaults, options);
1321
clearCache();
14-
return traverse(schema, opts, spec).value;
22+
let result = traverse(schema, opts, spec).value;
23+
if (opts.format === 'xml') {
24+
if (Object.keys(result).length > 1) {
25+
result = { [schema?.xml?.name || 'root']: result };
26+
}
27+
return builder.build(result);
28+
}
29+
return result;
1530
};
1631

1732
export function _registerSampler(type, sampler) {

src/samplers/array.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { traverse } from '../traverse';
2+
import { applyXMLAttributes } from '../utils';
3+
24
export function sampleArray(schema, options = {}, spec, context) {
35
const depth = (context && context.depth || 1);
46

@@ -22,7 +24,19 @@ export function sampleArray(schema, options = {}, spec, context) {
2224
for (let i = 0; i < arrayLength; i++) {
2325
let itemSchema = itemSchemaGetter(i);
2426
let { value: sample } = traverse(itemSchema, options, spec, {depth: depth + 1});
25-
res.push(sample);
27+
if (options?.format === 'xml') {
28+
const { value, propertyName } = applyXMLAttributes({value: sample}, itemSchema);
29+
if (propertyName) {
30+
if (!res?.[propertyName]) {
31+
res = { ...res, [propertyName]: [] };
32+
}
33+
res[propertyName].push(value);
34+
} else {
35+
res.push(sample);
36+
}
37+
} else {
38+
res.push(sample);
39+
}
2640
}
2741
return res;
2842
}

src/samplers/object.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { traverse } from '../traverse';
2+
import { applyXMLAttributes } from '../utils';
3+
24
export function sampleObject(schema, options = {}, spec, context) {
35
let res = {};
46
const depth = (context && context.depth || 1);
@@ -27,7 +29,17 @@ export function sampleObject(schema, options = {}, spec, context) {
2729
if (options.skipWriteOnly && sample.writeOnly) {
2830
return;
2931
}
30-
res[propertyName] = sample.value;
32+
33+
if (options?.format === 'xml') {
34+
const { propertyName: newPropertyName, value } = applyXMLAttributes(sample, schema.properties[propertyName], {propertyName});
35+
if (newPropertyName) {
36+
res[newPropertyName] = value;
37+
} else {
38+
res = { ...res, ...value };
39+
}
40+
} else {
41+
res[sample.propertyName] = sample.value;
42+
}
3143
});
3244
}
3345

src/utils.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,59 @@ export function popSchemaStack(seenSchemasStack, context) {
7171
if (context) seenSchemasStack.pop();
7272
}
7373

74+
export function getXMLAttributes(schema) {
75+
return {
76+
name: schema?.xml?.name || '',
77+
prefix: schema?.xml?.prefix || '',
78+
namespace: schema?.xml?.namespace || null,
79+
attribute: schema?.xml?.attribute ?? false,
80+
wrapped: schema?.xml?.wrapped ?? false,
81+
};
82+
}
83+
84+
export function applyXMLAttributes(result, schema, context) {
85+
const { value: oldValue } = result;
86+
const { propertyName: oldPropertyName } = context || {};
87+
const { name, prefix, namespace, attribute, wrapped } =
88+
getXMLAttributes(schema);
89+
let propertyName = name || oldPropertyName ? `${prefix ? prefix + ':' : ''}${name || oldPropertyName}` : null;
90+
91+
let value = typeof oldValue === 'object'
92+
? Array.isArray(oldValue)
93+
? [...oldValue]
94+
: { ...oldValue }
95+
: oldValue;
96+
97+
if (attribute && propertyName) {
98+
propertyName = `$${propertyName}`;
99+
}
100+
101+
if (namespace) {
102+
if (typeof value === 'object') {
103+
value[`$xmlns${prefix ? ':' + prefix : ''}`] = namespace;
104+
} else {
105+
value = { [`$xmlns${prefix ? ':' + prefix : ''}`]: namespace, ['#text']: value };
106+
}
107+
}
108+
109+
if (schema.type === 'array') {
110+
if (wrapped && Array.isArray(value)) {
111+
value = { [propertyName]: [...value] };
112+
} else if (!wrapped) {
113+
propertyName = null;
114+
}
115+
116+
if (schema.example !== undefined && !wrapped) {
117+
propertyName = schema.items.xml?.name || propertyName;
118+
}
119+
}
120+
121+
return {
122+
propertyName,
123+
value,
124+
};
125+
}
126+
74127
function hashCode(str) {
75128
var hash = 0;
76129
if (str.length == 0) return hash;

0 commit comments

Comments
 (0)