@krlwlfrt/xsdco
Version:
XSD converter
206 lines (176 loc) • 6.58 kB
text/typescript
/*
* Copyright (C) 2019, 2020 Karl-Philipp Wulfert
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Entity, isEntity, Property} from '@krlwlfrt/tsg';
import moment from 'moment';
import pad from 'pad';
import RandExp from 'randexp';
import {logger, TypeMap} from './common';
// require variable
// eslint-disable-next-line @typescript-eslint/no-require-imports
const faker = require('faker');
/**
* Generate a value for a property
* @param property Property to generate a value for
* @param typeMap Map of types by name
* @returns A value
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function generateValue(property: Property, typeMap: TypeMap): any {
let value;
if (typeof property.type.namespace === 'string' && !['xs', 'xsd'].includes(property.type.namespace) && property.type.name in typeMap) {
if (isEntity(typeMap[property.type.name])) {
if (typeof property.multiple !== 'undefined' && property.multiple) {
value = [];
for (let i = 0; i < faker.random.number({min: 2, max: 4}); i++) {
value.push(generateObjectValue(typeMap[property.type.name] as Entity, typeMap));
}
} else {
value = generateObjectValue(typeMap[property.type.name] as Entity, typeMap);
}
} else {
value = generateValue(typeMap[property.type.name] as Property, typeMap);
}
} else if (property.type.name === 'date') {
value = moment(faker.random.date)
.format('YYYY-MM-DD');
} else if (property.type.name === 'decimal') {
let totalDigits = 5;
let fractionDigits = 0;
if (Array.isArray(property.attributes)) {
for (const attribute of property.attributes) {
if (attribute.name === 'totalDigits') {
totalDigits = parseInt(attribute.value.toString(), 10);
}
if (attribute.name === 'fractionDigits') {
fractionDigits = parseInt(attribute.value.toString(), 10);
}
}
}
if (fractionDigits > 0) {
value = `${faker.random.number(Math.pow(10, totalDigits - fractionDigits))}.${faker.random.number(Math.pow(10, fractionDigits))}`;
} else {
value = faker.random.number(Math.pow(10, totalDigits - fractionDigits));
}
} else if (['short', 'unsignedByte'].includes(property.type.name)) {
value = faker.random.number(255);
} else if (property.type.name === 'int') {
value = faker.random.number(Number.MAX_SAFE_INTEGER);
} else if (property.type.name === 'string') {
value = faker.random.word();
let pattern = '';
let maxLength = -1;
if (Array.isArray(property.attributes)) {
for (const attribute of property.attributes) {
if (attribute.name === 'maxLength') {
maxLength = parseInt(attribute.value.toString(), 10);
}
if (attribute.name === 'pattern') {
pattern = attribute.value.toString();
}
}
}
if (pattern.length > 0) {
if (pattern === '\\d+') {
value = faker.random.number(Number.MAX_SAFE_INTEGER);
} else if (['....-..-..', '\\d\\d\\d\\d-\\d\\d-\\d\\d'].includes(pattern)) {
value = moment(faker.random.date)
.format('YYYY-MM-DD');
} else if (pattern === '\\d*') {
value = pad(100, faker.random.number(), '0');
if (maxLength >= 0) {
value = value
.toString()
.substr(value.toString.length - 1 - maxLength);
}
} else {
logger.info(`Pattern ${pattern} is unknown!`);
value = (new RandExp(new RegExp(pattern))).gen();
}
}
if (maxLength >= 0 && typeof value !== 'undefined') {
value = value
.toString()
.substr(0, maxLength);
}
}
if (typeof value === 'undefined') {
logger.info(`No mapping for ${property.name} with type ${property.type.name}`);
value = faker.random.alphaNumeric(100);
}
if (typeof property.multiple !== 'undefined' && property.multiple && !Array.isArray(value)) {
value = [value];
}
return value;
}
/**
* Generate a value for an object, e.g. generate a value for each property
* @param entity Entity to generate value for
* @param typeMap Map of types by name
* @returns An object
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function generateObjectValue(entity: Entity, typeMap: TypeMap): any {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const obj: any = {};
obj.$$name = entity.name;
for (const property of entity.properties) {
obj[property.name] = generateValue(property, typeMap);
}
return obj;
}
/**
* Generate XML for an object
* @param object Object to generate an XML for
* @param includeHead Whether or not to include XML head in the output
* @param recursionDepth Counter for recursion depth
* @returns XML
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function generateXml(object: any, includeHead = true, recursionDepth = 0) {
let output = '';
if (includeHead) {
output = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n';
output += `<${object.$$name}`;
for (const key in object) {
if (!{}.hasOwnProperty.call(object, key) || key.indexOf('$') !== 0 || key === '$$name') {
continue;
}
output += ` ${key.substring(1)}="${object[key]}"`;
}
output += '>\n';
}
for (const key in object) {
if (!{}.hasOwnProperty.call(object, key) || key.indexOf('$') === 0) {
continue;
}
if (Array.isArray(object[key])) {
for (const item of object[key]) {
output += `<${key}>\n`;
output += generateXml(item, false, recursionDepth + 1);
output += `</${key}>\n`;
}
} else if (typeof object[key] === 'object') {
output += `<${key}>\n`;
output += generateXml(object[key], false, recursionDepth + 1);
output += `</${key}>\n`;
} else {
output += `<${key}>${object[key].toString()}</${key}>\n`;
}
}
if (includeHead) {
output += `</${object.$$name}>`;
}
return output;
}