@postman/wsdl-to-postman
Version:
Convert a given WSDL specification (1.1) to Postman Collection
1,258 lines (1,176 loc) • 70.4 kB
JavaScript
const { ElementResolver } = require('./ElementResolver'),
_ = require('lodash');
const Parser = require('fast-xml-parser').j2xParser,
parserOptions = {
ignoreAttributes: false,
cdataTagName: '__cdata',
format: true,
indentBy: ' ',
supressEmptyNode: false
},
{
getLastSegmentURL
} = require('./textUtils'),
{
ERROR_ELEMENT_IDENTIFIER
} = require('../constants/processConstants'),
{
getArrayFrom,
getDeepCopyOfObject,
getShallowCopyOfObject
} = require('./objectUtils'),
{
getXMLAttributeByName,
getXMLNodeByName,
getQNamePrefix,
XML_NAMESPACE_SEPARATOR
} = require('./XMLParsedUtils'),
Element = require('../WSDLObject').Element,
{
orderSchemasAccordingToDependencies
} = require('../../lib/utils/orderSchemasByDependency'),
WsdlError = require('../WsdlError'),
UserError = require('../UserError'),
{
isKnownType
} = require('./knownTypes'),
{
COMPLEX_TYPE_TAG,
GROUP_TAG,
SIMPLE_TYPE_TAG,
ATTRIBUTE_ELEMENT,
ATTRIBUTE_TYPE_TAG
} = require('../constants/XSDConstants'),
TYPES_TAG = 'types',
ATTRIBUTE_TARGET_NAMESPACE = 'targetNamespace',
SCHEMA_TAG = 'schema',
MESSAGE_TAG = 'message',
ATTRIBUTE_NAME = 'name',
ATTRIBUTE_PART = 'part',
ATTRIBUTE_TYPE = 'type',
traverseUtility = require('traverse'),
IS_KNOWN_TYPE = 'knownType',
IS_ELEMENT = 'isElement',
IS_SIMPLE_TYPE = 'isSimpleType',
IS_COMPLEX_TYPE = 'isComplexType',
ANONIMOUS = 'anonimous',
REPLACE_CASES = [{
tagName: 'all',
newTagName: 'sequence'
}],
DEFINITIONS_FILTER = '#/definitions/',
PARSER_ATTRIBUTE_NAME_PLACE_HOLDER = '@_',
{
createErrorElement
} = require('./WSDLElementUtils'),
{
sortElementsAccordingToDependencies
} = require('./sortSchemaItemsUtils'),
{
XSDToJsonSchemaParser
} = require('../XSDToJsonSchemaParser'),
oneOfIdentifier = 'oneOf',
anyOfIdentifier = 'anyOf',
XML_NAMESPACE = 'xmlns';
/**
* Class to map types schemas from xml parsed document
* into an array of elements nodes
*/
class SchemaBuilderXSD {
/**
* Build the WSDLObject elements
* @param {object} parsedXml the binding operation object
* @param {string} principalPrefix the principal prefix of document
* @param {string} wsdlRoot the root depending on version
* @param {WSDLObject} wsdlObject the wsdlObject parsed object
* @param {string} parserPlaceholder the corresponding parser prefix for ATTRIBUTEs
* @returns {[Element]} the information of the types
*/
getElements(parsedXml, principalPrefix, wsdlRoot, wsdlObject, parserPlaceholder) {
if (!parsedXml || typeof parsedXml !== 'object') {
throw new UserError('Provided WSDL definition is invalid XML.');
}
let elementsFromMessages = [],
xsdParser = new XSDToJsonSchemaParser(),
allElements = {},
resolver;
allElements.elements = [];
allElements.simpleTypeElements = [];
allElements.complexTypeElements = [];
allElements.groupElements = [];
allElements.globalAttributesElements = [];
const types = this.getTypes(parsedXml, principalPrefix, wsdlRoot);
types.forEach((type) => {
let schemaTags = [],
jsonSchemas,
mergedDefinitionsSchema,
schemaStrings = [];
schemaTags = this.getSchemasInformation(type, wsdlObject, parserPlaceholder);
const sortedSchemas = orderSchemasAccordingToDependencies(schemaTags, parserPlaceholder,
wsdlObject.allNameSpaces);
sortedSchemas.forEach((schemaTag) => {
schemaStrings.push(this.getXMLSchemaProcessed(schemaTag.foundSchemaTag, schemaTag.foundLocalSchemaNamespace,
schemaTag.targetNamespace, schemaTag.tnsNamespace, parserPlaceholder, wsdlObject.allNameSpaces));
});
jsonSchemas = xsdParser.parseAllSchemas(schemaStrings);
mergedDefinitionsSchema = this.mergeAllSchemaDefinitionsInOne(jsonSchemas);
sortedSchemas.forEach((schema, index) => {
this.getWSDLElementsFromJsonSchema({
jsonSchema: mergedDefinitionsSchema, schemaTagInformation: schema,
parserPlaceholder,
elements: allElements.elements,
simpleTypeElements: allElements.simpleTypeElements,
complexTypeElements: allElements.complexTypeElements,
groupElements: allElements.groupElements,
globalAttributesElements: allElements.globalAttributesElements,
currentSchemaIndex: index
});
});
});
resolver = new ElementResolver(allElements);
resolver.resolveAll();
elementsFromMessages = this.getElementsFromMessages(parsedXml, principalPrefix,
allElements.elements, allElements.simpleTypeElements, allElements.complexTypeElements,
parserPlaceholder, wsdlRoot);
return allElements.elements.concat(elementsFromMessages);
}
/**
* Takes in an array of JsonSchemas and merge them into one
* takes the global information from the first one
* @param {Array} jsonSchemas Json Schemas array
* @returns {object} the merged jsonSchema
*/
mergeAllSchemaDefinitionsInOne(jsonSchemas) {
let mergedDefinitionsSchema;
if (jsonSchemas && jsonSchemas.length > 0) {
mergedDefinitionsSchema = getDeepCopyOfObject(jsonSchemas[0]);
var definitions = {};
jsonSchemas.forEach((jsonSchema) => {
Object.keys(jsonSchema.definitions).forEach((defName) => {
if (!definitions[defName]) {
definitions[defName] = jsonSchema.definitions[defName];
}
else {
definitions[jsonSchema.$id + '/' + defName] = jsonSchema.definitions[defName];
}
});
});
mergedDefinitionsSchema.definitions = definitions;
}
return mergedDefinitionsSchema;
}
/**
* Returns all the schema tags information
* tag information namespace definition and target Namespace
* @param {object} typeElement the element "type" from wsdl
* @param {WSDLObject} wsdlObject the whole wsdl object
* @param {string} parserPlaceholder the corresponding parser prefix for ATTRIBUTE
* @returns {[Element]} the information of the types
*/
getSchemasInformation(typeElement, wsdlObject, parserPlaceholder) {
let schemaTags = [],
globalSchemaTag,
schemasToReturn = [],
schemasWithLocalDefinition,
uniqueTargetNamespaces,
targetNamespaces;
if (wsdlObject.schemaNamespace) {
globalSchemaTag =
getArrayFrom(typeElement[wsdlObject.schemaNamespace.prefixFilter + SCHEMA_TAG]);
}
if (globalSchemaTag) {
globalSchemaTag.forEach((schemaTag) => {
let targetNamespace = getXMLAttributeByName(schemaTag, parserPlaceholder, ATTRIBUTE_TARGET_NAMESPACE),
tnsNamespace = Array.isArray(wsdlObject.allNameSpaces) && wsdlObject.allNameSpaces.filter((ns) => {
return targetNamespace === ns.url && ns.key !== ATTRIBUTE_TARGET_NAMESPACE;
});
schemaTags.push({
foundSchemaTag: schemaTag,
foundLocalSchemaNamespace: wsdlObject.schemaNamespace,
targetNamespace,
tnsNamespace
});
});
}
schemasWithLocalDefinition = this.getSchemaInfoFromLocalDeclaredNamespacesDefinition(wsdlObject, typeElement,
parserPlaceholder);
if (schemasWithLocalDefinition) {
schemasWithLocalDefinition.forEach((schema) => {
schemaTags.push(schema);
});
targetNamespaces = schemaTags.map((tag) => {
return tag.targetNamespace;
});
uniqueTargetNamespaces = this.getUniqueElementsFromArray(targetNamespaces);
uniqueTargetNamespaces.forEach((uniqueTN) => {
schemasToReturn.push(schemaTags.find((schema) => {
return uniqueTN === schema.targetNamespace;
}));
});
}
else {
return schemaTags;
}
return schemasToReturn;
}
/**
* Returns a filtered array with no duplicates
* @param {Array} array to get unique elements
* @returns {Array} the filtered array
*/
getUniqueElementsFromArray(array) {
return array.filter((value, index, self) => {
return self.indexOf(value) === index;
});
}
/**
* Returns the schema tag and namespace definition locally defined (inside the schema tag)
* @param {WSDLObject} wsdlObject the wsdlObject parsed object
* @param {object} type the type element from the wsdl (element tag)
* @param {string} parserPlaceholder the corresponding parser prefix for ATTRIBUTE
* @returns {[Element]} the information of the types
*/
getSchemaInfoFromLocalDeclaredNamespacesDefinition(wsdlObject, type, parserPlaceholder) {
if (wsdlObject.localSchemaNamespaces) {
let result = [];
for (let index = 0; index < wsdlObject.localSchemaNamespaces.length; index++) {
let schemasInlocal =
getArrayFrom(type[wsdlObject.localSchemaNamespaces[index].prefixFilter + SCHEMA_TAG]);
schemasInlocal.forEach((foundSchema) => {
result.push({
foundSchemaTag: foundSchema,
foundLocalSchemaNamespace: wsdlObject.localSchemaNamespaces[index],
targetNamespace: getXMLAttributeByName(foundSchema,
parserPlaceholder, ATTRIBUTE_TARGET_NAMESPACE)
});
});
}
return result;
}
}
/**
* Gets the wsdlobject elements defined in messages instead of
* in the types tag.
* creates elements for simple types complex types and elements of the wsdl
* @param {object} parsedXML the binding operation object
* @param {string} principalPrefix the principal prefix of document
* @param {Array} elementsInTypes the elements from the types tag
* @param {Array} simpleTypes the simple types from the types tag
* @param {Array} complexTypes the complex types from the types tag
* @param {string} parserPlaceholder the corresponding parser prefix for ATTRIBUTE
* @param {string} wsdlRoot the corresponding wsdl root definitions or descriptions
* @returns {[Element]} the information of the types
*/
getElementsFromMessages(parsedXML, principalPrefix, elementsInTypes, simpleTypes, complexTypes, parserPlaceholder,
wsdlRoot) {
let filtered = '',
newElements = [];
const definitions = parsedXML[principalPrefix + wsdlRoot],
messages = getArrayFrom(getXMLNodeByName(definitions, principalPrefix, MESSAGE_TAG));
if (!messages) {
return newElements;
}
filtered = messages.filter((message) => {
let part = getXMLNodeByName(message, principalPrefix, ATTRIBUTE_PART) || {},
hasPartKey = Object.keys(part).find((key) => {
if (key === `${parserPlaceholder}type`) {
return true;
}
});
if (part.length > 1 || hasPartKey) {
return message;
}
});
filtered.forEach((message) => {
let parts = [],
wsdlElement = new Element();
wsdlElement.name = getXMLAttributeByName(message, parserPlaceholder, ATTRIBUTE_NAME);
wsdlElement.type = ANONIMOUS;
wsdlElement.isComplex = true;
wsdlElement.minOccurs = 0;
wsdlElement.maxOccurs = 1;
wsdlElement.children = [];
parts = getArrayFrom(getXMLNodeByName(message, principalPrefix, ATTRIBUTE_PART));
parts.forEach((part) => {
let realPartTypeorelement = '',
partType = getXMLAttributeByName(part, parserPlaceholder, ATTRIBUTE_TYPE),
partName = getXMLAttributeByName(part, parserPlaceholder, ATTRIBUTE_NAME);
if (!partType) {
realPartTypeorelement = getXMLAttributeByName(part, parserPlaceholder, ATTRIBUTE_ELEMENT);
}
else {
realPartTypeorelement = partType;
}
realPartTypeorelement = _.split(realPartTypeorelement, XML_NAMESPACE_SEPARATOR)[1];
if (realPartTypeorelement) {
let foundType = this.findMessageParameterAndType(realPartTypeorelement, elementsInTypes,
simpleTypes, complexTypes);
if (foundType.typeOfType === IS_KNOWN_TYPE) {
let element = new Element();
element.name = partName;
element.type = realPartTypeorelement;
element.children = [];
wsdlElement.children.push(element);
}
if (foundType.typeOfType === IS_COMPLEX_TYPE ||
foundType.typeOfType === IS_SIMPLE_TYPE ||
foundType.typeOfType === IS_ELEMENT) {
let type = foundType.type;
if (type) {
let element = getShallowCopyOfObject(type);
wsdlElement.children.push(element);
}
}
}
});
newElements.push(wsdlElement);
});
return newElements;
}
/**
* Finds the type of the parameter that could be:
* element simple type complex type or an scalar type
* in the types tag.
* creates elements for simple types complex types and elements of the wsdl
* @param {string} typeOrElementName the name of the parameter (type or element)
* @param {Array} elementsInTypes the elements from the types tag
* @param {Array} simpleTypes the simple types from the types tag
* @param {Array} complexTypes the complex types from the types tag
* @returns {[Object]} the type of the parameter and the object of the parameter
*/
findMessageParameterAndType(typeOrElementName, elementsInTypes, simpleTypes, complexTypes) {
let found;
if (isKnownType(typeOrElementName)) {
return {
typeOfType: IS_KNOWN_TYPE
};
}
if (elementsInTypes) {
found = elementsInTypes.find((element) => {
return element.name === typeOrElementName;
});
if (found) {
return {
typeOfType: IS_ELEMENT,
type: found
};
}
}
if (simpleTypes) {
found = simpleTypes.find((element) => {
return element.name === typeOrElementName;
});
if (found) {
return {
typeOfType: IS_SIMPLE_TYPE,
type: found
};
}
}
if (complexTypes) {
found = complexTypes.find((element) => {
return element.name === typeOrElementName;
});
if (found) {
return {
typeOfType: IS_COMPLEX_TYPE,
type: found
};
}
}
return '';
}
/**
* identifies the namespaces that we have to add to the schema
* so the xsd2json conversion success.
* @param {Array} wsdlAllNamespaces All the namespaces in the WSDL document
* @param {object} schemaTag the wsdl schema information object
* @param {string} parserPlaceholder the corresponding parser prefix for ATTRIBUTEs
* @returns {array} the namespaces to add into the schema
*/
getAdditionalNamespaces(wsdlAllNamespaces, schemaTag, parserPlaceholder) {
if (!wsdlAllNamespaces) {
return [];
}
let additional = new Set();
traverseUtility(schemaTag).forEach((property) => {
if (property && property[parserPlaceholder + 'type']) {
let prefix = getQNamePrefix(property[parserPlaceholder + 'type']),
found = wsdlAllNamespaces.find((namespace) => {
return namespace.key === prefix;
});
if (found) {
additional.add(found);
}
}
});
return [...additional];
}
/**
* Takes the schema object add the needed namespaces
* and return the xml of the schema
* @param {object} schemaTag the wsdl schema information object
* @param {NameSpace} schemaNamespace the schema namespace information from the wsdl
* @param {NameSpace} tnsNamespaceURL the this namespace url
* @param {array} tnsNamespace the this namespace object
* @param {string} parserPlaceholder the corresponding parser prefix for ATTRIBUTEs
* @param {Array} wsdlAllNamespaces All the namespaces in the WSDL document
* @returns {string} the xml representation of the object
*/
getXMLSchemaProcessed(schemaTag, schemaNamespace, tnsNamespaceURL, tnsNamespace, parserPlaceholder,
wsdlAllNamespaces) {
let localSchemaTag = {
...schemaTag
},
objectSchema = {},
schema,
additionalNS;
if (schemaNamespace.key === '') {
localSchemaTag[parserPlaceholder + XML_NAMESPACE] = undefined;
}
else {
localSchemaTag[parserPlaceholder + XML_NAMESPACE + XML_NAMESPACE_SEPARATOR + schemaNamespace.key] =
schemaNamespace.url;
}
if (tnsNamespace && tnsNamespace.length > 0) {
// assign tns namespace for current schema if present at wsdl root level
tnsNamespace.forEach((sameURLNS) => {
localSchemaTag[parserPlaceholder + XML_NAMESPACE + XML_NAMESPACE_SEPARATOR + sameURLNS.key] = sameURLNS.url;
});
}
else {
localSchemaTag[parserPlaceholder + XML_NAMESPACE + XML_NAMESPACE_SEPARATOR + 'tns'] = tnsNamespaceURL;
}
additionalNS = this.getAdditionalNamespaces(wsdlAllNamespaces, schemaTag, parserPlaceholder);
additionalNS.forEach((namespace) => {
if (!localSchemaTag[parserPlaceholder + XML_NAMESPACE + XML_NAMESPACE_SEPARATOR + namespace.key]) {
localSchemaTag[parserPlaceholder + XML_NAMESPACE + XML_NAMESPACE_SEPARATOR + namespace.key] = namespace.url;
}
});
objectSchema = {};
objectSchema[schemaNamespace.prefixFilter + SCHEMA_TAG] = localSchemaTag;
schema = this.parseObjectToXML(objectSchema);
REPLACE_CASES.forEach((replaceCase) => {
schema = this.replaceTagInSchema(schema, schemaNamespace, replaceCase.tagName, replaceCase.newTagName);
});
return schema;
}
/**
* Takes an schema in string xml and replace the tagName with newTagName
* @param {string} schema schema in xml representation
* @param {object} schemaNamespace the schema information (prefix)
* @param {string} tagName the tag to substitute
* @param {string} newTagName the new tag
* @returns {string} the modified string xml
*/
replaceTagInSchema(schema, schemaNamespace, tagName, newTagName) {
if (!schema.includes(`<${schemaNamespace.prefixFilter}${tagName}>`)) {
return schema;
}
let newSchema;
if (schemaNamespace.prefixFilter !== '') {
let openTagRegexp = new RegExp(`<${schemaNamespace.prefixFilter}?${tagName}>`, 'g'),
closeTagRegexp = new RegExp(`</${schemaNamespace.prefixFilter}?${tagName}>`, 'g');
newSchema = schema.replace(openTagRegexp, `<${schemaNamespace.prefixFilter}${newTagName}>`);
newSchema = newSchema.replace(closeTagRegexp, `</${schemaNamespace.prefixFilter}${newTagName}>`);
}
else {
let openTagRegexp = new RegExp(`<${tagName}>`, 'g'),
closeTagRegexp = new RegExp(`</${tagName}>`, 'g');
newSchema = schema.replace(openTagRegexp, `<${newTagName}>`);
newSchema = newSchema.replace(closeTagRegexp, `</${newTagName}>`);
}
return newSchema;
}
/**
* Takes a jsonObject and parses to xml
* @param {object} jsonObject the object to convert into xml
* @returns {string} the xml representation of the object
*/
parseObjectToXML(jsonObject) {
if (jsonObject === null || jsonObject === undefined) {
throw new UserError('Provided WSDL definition is invalid.');
}
let parser = new Parser(parserOptions),
xml = parser.parse(jsonObject);
return xml;
}
/**
* Build the WSDLObject elements
* @param {string} jsonSchema the parsed jsonSchema
* @param {string} schemaTagInformation the schema tag information
* @param {string} parserPlaceholder the corresponding parser prefix for ATTRIBUTEs
* @param {Array} elements the WSDL Schema Elements objects
* @param {Array} simpleTypeElements the WSDL Schema simple types objects
* @param {Array} complexTypeElements the WSDL Schema complex types objects
* @param {Array} groupElements the WSDL Schema group objects
* @returns {[Element]} the information of the types
*/
getWSDLElementsFromJsonSchema({ jsonSchema, schemaTagInformation, parserPlaceholder, elements,
simpleTypeElements, complexTypeElements, groupElements, globalAttributesElements, currentSchemaIndex }) {
if (!jsonSchema || typeof jsonSchema !== 'object') {
return {
elements: [],
simpleTypeElements: [],
complexTypeElements: []
};
}
let complexTypesFromCurrentTag = [],
simpleTypesFromCurrentTag = [],
elementTypesFromCurrentTag = [],
groupsFromCurrentTag = [],
globalAttributesFromCurrentTag = [],
jsonSchemaComplexTypesFromCurrentTag,
jsonSchemaSimpleTypesFromCurrentTag,
jsonSchemaGroupsFromCurrentTag,
jsonSchemaGlobalAttributesFromCurrentTag,
previousPlusCurrentSimple,
previousPlusCurrentComplex,
jsonSchemaElementsFromCurrentTag,
targetNamespace = schemaTagInformation.targetNamespace,
schemaPrefixFilter = schemaTagInformation.foundLocalSchemaNamespace.prefixFilter,
jsonSchemaClxTypesProcessed,
jsonSchemaGroupsProcessed,
jsonSchemaGlobalAttributesProcessed,
jsonSchemaSimpleTypesProcessed;
const definitionsNames = Object.keys(jsonSchema.definitions),
globalAttributes = jsonSchema.globalAttributes ?
Object.keys(jsonSchema.globalAttributes) :
[],
scTag = schemaTagInformation.foundSchemaTag,
schemaAttributes = {
attributeFormDefault: _.toLower(_.get(scTag, PARSER_ATTRIBUTE_NAME_PLACE_HOLDER +
'attributeFormDefault')) === 'qualified',
elementFormDefault: _.toLower(_.get(scTag, PARSER_ATTRIBUTE_NAME_PLACE_HOLDER +
'elementFormDefault')) === 'qualified',
nsPrefix: this.getNamespacePrefix(schemaTagInformation.tnsNamespace, targetNamespace)
};
// set current tnsNamespace under this
this.tnsNamespace = schemaTagInformation.tnsNamespace;
complexTypesFromCurrentTag = getArrayFrom(this.getComplexTypesFromSchema(scTag, schemaPrefixFilter));
simpleTypesFromCurrentTag = getArrayFrom(this.getSimpleTypesFromSchema(scTag, schemaPrefixFilter));
elementTypesFromCurrentTag = getArrayFrom(this.getElementsFromSchema(scTag, schemaPrefixFilter));
groupsFromCurrentTag = getArrayFrom(this.getGroupsFromSchema(scTag, schemaPrefixFilter));
globalAttributesFromCurrentTag = getArrayFrom(this.getGlobalAttributesFromSchema(scTag, schemaPrefixFilter));
complexTypesFromCurrentTag = complexTypesFromCurrentTag ? complexTypesFromCurrentTag : [];
simpleTypesFromCurrentTag = simpleTypesFromCurrentTag ? simpleTypesFromCurrentTag : [];
elementTypesFromCurrentTag = elementTypesFromCurrentTag ? elementTypesFromCurrentTag : [];
groupsFromCurrentTag = groupsFromCurrentTag ? groupsFromCurrentTag : [];
globalAttributesFromCurrentTag = globalAttributesFromCurrentTag ? globalAttributesFromCurrentTag : [];
jsonSchemaElementsFromCurrentTag = this.getTypesFromDefinitions(jsonSchema, elementTypesFromCurrentTag,
definitionsNames, parserPlaceholder, currentSchemaIndex);
jsonSchemaComplexTypesFromCurrentTag = this.getTypesFromDefinitions(jsonSchema, complexTypesFromCurrentTag,
definitionsNames, parserPlaceholder, currentSchemaIndex);
jsonSchemaSimpleTypesFromCurrentTag = this.getTypesFromDefinitions(jsonSchema, simpleTypesFromCurrentTag,
definitionsNames, parserPlaceholder, currentSchemaIndex);
jsonSchemaGroupsFromCurrentTag = this.getTypesFromDefinitions(jsonSchema, groupsFromCurrentTag,
definitionsNames, parserPlaceholder, currentSchemaIndex);
jsonSchemaGlobalAttributesFromCurrentTag = this.getTypesFromGlobaAttributes(
jsonSchema,
globalAttributesFromCurrentTag,
globalAttributes,
parserPlaceholder
);
jsonSchemaClxTypesProcessed = this.getPreviousProcessedDefinitionsFromJsonSchema(jsonSchema,
complexTypeElements,
definitionsNames);
jsonSchemaSimpleTypesProcessed = this.getPreviousProcessedDefinitionsFromJsonSchema(jsonSchema,
simpleTypeElements,
definitionsNames);
jsonSchemaGroupsProcessed = this.getPreviousProcessedDefinitionsFromJsonSchema(jsonSchema,
groupElements,
definitionsNames);
jsonSchemaGlobalAttributesProcessed = this.getPreviousProcessedDefinitionsFromJsonSchema(jsonSchema,
globalAttributesElements,
definitionsNames);
if (jsonSchemaSimpleTypesFromCurrentTag && jsonSchemaSimpleTypesFromCurrentTag.length > 0) {
this.processComplexOrSimpleTypesToElement(jsonSchemaSimpleTypesFromCurrentTag, targetNamespace,
simpleTypeElements, schemaAttributes);
}
if (jsonSchemaGroupsFromCurrentTag && jsonSchemaGroupsFromCurrentTag.length > 0) {
this.processComplexOrSimpleTypesToElement(jsonSchemaGroupsFromCurrentTag, targetNamespace, groupElements,
schemaAttributes);
}
previousPlusCurrentSimple = jsonSchemaSimpleTypesFromCurrentTag.concat(jsonSchemaSimpleTypesProcessed);
previousPlusCurrentSimple = previousPlusCurrentSimple.concat(jsonSchemaGroupsFromCurrentTag);
previousPlusCurrentSimple = previousPlusCurrentSimple.concat(jsonSchemaGroupsProcessed);
if (jsonSchemaGlobalAttributesFromCurrentTag && jsonSchemaGlobalAttributesFromCurrentTag.length > 0) {
this.processComplexOrSimpleTypesToElement(jsonSchemaGlobalAttributesFromCurrentTag,
jsonSchemaClxTypesProcessed,
jsonSchemaSimpleTypesProcessed, targetNamespace, globalAttributesElements, schemaAttributes);
}
previousPlusCurrentSimple = previousPlusCurrentSimple.concat(jsonSchemaGlobalAttributesFromCurrentTag);
previousPlusCurrentSimple = previousPlusCurrentSimple.concat(jsonSchemaGlobalAttributesProcessed);
if (jsonSchemaComplexTypesFromCurrentTag && jsonSchemaComplexTypesFromCurrentTag.length > 0) {
this.processComplexOrSimpleTypesToElement(jsonSchemaComplexTypesFromCurrentTag,
targetNamespace, complexTypeElements, schemaAttributes);
}
previousPlusCurrentComplex = jsonSchemaComplexTypesFromCurrentTag.concat(jsonSchemaClxTypesProcessed);
if (jsonSchemaElementsFromCurrentTag && jsonSchemaElementsFromCurrentTag.length > 0) {
this.processElementsToWSDElements(jsonSchemaElementsFromCurrentTag, previousPlusCurrentComplex,
previousPlusCurrentSimple, targetNamespace, elements, schemaAttributes);
}
return {
elements,
simpleTypeElements,
complexTypeElements,
groupElements,
globalAttributes
};
}
/**
* Process the wsdl elements into WSDLObject elements
* always returns an array
* @param {Array} elementsFromWSDL the elements from the schema
* @param {object} complexTypes the list of processed complex types
* @param {object} simpleTypes the list of processed simple types
* @param {object} targetNamespace the found namespace in wsdl
* @param {string} elements the elements to fill in
* @param {object} schemaAttributes schema attributes corresponding to current elements
* @returns {undefined} returns nothing
*/
processElementsToWSDElements(elementsFromWSDL, complexTypes, simpleTypes, targetNamespace, elements,
schemaAttributes = {}) {
let sorted = sortElementsAccordingToDependencies(elementsFromWSDL);
sorted.forEach((element) => {
let wsdlElement = new Element(),
lookedReferences = [];
this.searchAndAssignComplex(element,
complexTypes,
simpleTypes, elements, lookedReferences, true);
wsdlElement.namespace = targetNamespace;
wsdlElement.name = this.removeSchemaIDFromName(element.name);
wsdlElement.type = this.getTypeOfElement(element);
wsdlElement.isComplex = wsdlElement.type === 'complex';
wsdlElement.isElement = true;
wsdlElement.minOccurs = this.getMinOccursOfElement(element, wsdlElement.name);
wsdlElement.maxOccurs = this.getMaxOccursOfElement(element, wsdlElement.name);
wsdlElement.minimum = element.minimum;
wsdlElement.maximum = element.maximum;
wsdlElement.maxLength = element.maxLength;
wsdlElement.minLength = element.minLength;
wsdlElement.contentEncoding = element.contentEncoding;
wsdlElement.pattern = element.pattern;
wsdlElement.enum = element.enum;
wsdlElement.attributeFormDefault = schemaAttributes.attributeFormDefault;
wsdlElement.elementFormDefault = schemaAttributes.elementFormDefault;
wsdlElement.nsPrefix = schemaAttributes.nsPrefix;
this.getChildren(element, wsdlElement, elements, targetNamespace);
elements.push(wsdlElement);
});
}
/**
* Provides mathcing namespace prefix for given URL
*
* @param {Array} namespaces - Namespaces defined for current schema
* @param {String} namespaceUrl - Namespace URL
* @returns {String} Namespace prefix matching with current namespace URL
*/
getNamespacePrefix (namespaces, namespaceUrl) {
let nsPrefix = '';
_.forEach(namespaces, (ns) => {
if (_.get(ns, 'url') === namespaceUrl) {
(_.has(ns, 'key') && typeof ns.key === 'string') && (nsPrefix = ns.key);
return true;
}
});
return nsPrefix;
}
/**
* Removes the schema id found in duplicated elements
* @param {string} elementName the name of the WSDLElement
* @returns {string} returns the name without the schema id
*/
removeSchemaIDFromName(elementName) {
return getLastSegmentURL(elementName);
}
/**
* Process the wsdl simple or complex types into WSDLObject elements
* always returns an array
* @param {Array} origin the elements from the schema to traverse
* @param {object} targetNamespace the found namespace in wsdl
* @param {string} typeElements the elements to fill in
* @param {object} schemaAttributes schema attributes corresponding to current elements
* @returns {undefined} returns nothing
*/
processComplexOrSimpleTypesToElement(origin, targetNamespace, typeElements, schemaAttributes = {}) {
let sorted = sortElementsAccordingToDependencies(origin);
sorted.forEach((element) => {
let wsdlElement = new Element();
wsdlElement.namespace = targetNamespace;
wsdlElement.name = element.name;
wsdlElement.type = this.getTypeOfElement(element);
wsdlElement.isElement = false;
wsdlElement.isComplex = wsdlElement.type === 'complex';
wsdlElement.minOccurs = this.getMinOccursOfElement(element, wsdlElement.name);
wsdlElement.maxOccurs = this.getMaxOccursOfElement(element, wsdlElement.name);
wsdlElement.minimum = element.minimum;
wsdlElement.maximum = element.maximum;
wsdlElement.contentEncoding = element.contentEncoding;
wsdlElement.maxLength = element.maxLength;
wsdlElement.minLength = element.minLength;
wsdlElement.pattern = element.pattern;
wsdlElement.enum = element.enum;
wsdlElement.attributeFormDefault = schemaAttributes.attributeFormDefault;
wsdlElement.elementFormDefault = schemaAttributes.elementFormDefault;
wsdlElement.nsPrefix = schemaAttributes.nsPrefix;
this.getChildren(element, wsdlElement, typeElements, targetNamespace);
typeElements.push(wsdlElement);
});
}
/**
* Find the objects from definitions
* receives the names and find them in definitions
* always returns an array
* @param {object} parsedSchema the parsed schema element from a WSDL File
* @param {object} typesFromWSDL the list to filter could be simple types complex or elements
* @param {object} definitionsNames the found names in definitions
* @param {string} parserPlaceholder the parser placeholder
* @param {number} currentSchemaIndex the current schema index we are processing
* @returns {Array} definitionsElements the objects from definitions
*/
getTypesFromDefinitions(parsedSchema, typesFromWSDL, definitionsNames, parserPlaceholder,
currentSchemaIndex) {
let namesFromWSDL = [],
definitionsElements,
allNames = [],
found = this.getTypesFromDefinitionsBySchemaAndName(parsedSchema, typesFromWSDL, definitionsNames,
parserPlaceholder, currentSchemaIndex);
if (found.length === 0) {
namesFromWSDL = typesFromWSDL.map((type) => {
return getXMLAttributeByName(type, parserPlaceholder, ATTRIBUTE_NAME);
});
allNames = namesFromWSDL;
}
else {
typesFromWSDL.forEach((type) => {
let localName = getXMLAttributeByName(type, parserPlaceholder, ATTRIBUTE_NAME),
prevFound = found.find((foundElements) => {
return foundElements.name === 'schema_' + currentSchemaIndex + '.json/' + localName;
});
if (!prevFound) {
namesFromWSDL.push(localName);
}
});
allNames = namesFromWSDL;
}
definitionsElements = definitionsNames.filter((definitionName) => {
return allNames.includes(definitionName);
}).map((definitionName) => {
return {
...parsedSchema.definitions[definitionName],
name: definitionName,
fullName: `${parsedSchema.$id}#/definitions/${definitionName}`
};
});
return definitionsElements.concat(found);
}
/**
* Find the objects from definitions using the schema id and name
* receives the names and find them in definitions
* always returns an array
* @param {object} parsedSchema the parsed schema element from a WSDL File
* @param {object} typesFromWSDL the list to filter could be simple types complex or elements
* @param {object} definitionsNames the found names in definitions
* @param {string} parserPlaceholder the parser placeholder
* @param {number} currentSchemaIndex the current schema index we are processing
* @returns {Array} definitionsElements the objects from definitions
*/
getTypesFromDefinitionsBySchemaAndName(parsedSchema, typesFromWSDL, definitionsNames, parserPlaceholder,
currentSchemaIndex) {
let namesFromWSDL,
definitionsElements,
allNames = [];
namesFromWSDL = typesFromWSDL.map((type) => {
let localName = getXMLAttributeByName(type, parserPlaceholder, ATTRIBUTE_NAME);
return 'schema_' + currentSchemaIndex + '.json/' + localName;
});
allNames = namesFromWSDL;
definitionsElements = definitionsNames.filter((definitionName) => {
return allNames.includes(definitionName);
}).map((definitionName) => {
return {
...parsedSchema.definitions[definitionName],
name: definitionName,
fullName: `${parsedSchema.$id}#/definitions/${definitionName}`
};
});
return definitionsElements;
}
/**
* Find the objects from globalAttributes
* receives the names and find them in globalAttributes
* always returns an array
* @param {object} parsedSchema the parsed schema element from a WSDL File
* @param {object} typesFromWSDL the list to filter could be simple types complex or elements
* @param {object} globalAttributesNames the found names in globalAttributes
* @param {string} parserPlaceholder the parser placeholder
* @param {number} currentSchemaIndex the current schema index we are processing
* @returns {Array} globalAttributesElements the objects from definitions
*/
getTypesFromGlobaAttributes(parsedSchema, typesFromWSDL, globalAttributesNames, parserPlaceholder) {
let namesFromWSDL,
globalAttributesElements,
allNames = [];
namesFromWSDL = typesFromWSDL.map((type) => {
return getXMLAttributeByName(type, parserPlaceholder, ATTRIBUTE_NAME);
});
allNames = namesFromWSDL;
globalAttributesElements = globalAttributesNames.filter((globalAttributeName) => {
return allNames.includes(globalAttributeName);
}).map((globalAttributeName) => {
return {
...parsedSchema.globalAttributes[globalAttributeName],
name: globalAttributeName,
fullName: `${parsedSchema.$id}#/globalAttributes/${globalAttributeName}`
};
});
return globalAttributesElements;
}
/**
* Find the previous processed elements (simple or complex)
* receives the names and find them in definitions
* always returns an array
* @param {object} parsedSchema the parsed schema element from a WSDL File
* @param {Array} previousProcessedItems simple or complex types already processed
* @param {Array} definitionsNames the found names in definitions
* @returns {Array} definitionsElements the objects from definitions
*/
getPreviousProcessedDefinitionsFromJsonSchema(parsedSchema, previousProcessedItems, definitionsNames) {
let definitionsElements,
namesPreviousProcessed;
namesPreviousProcessed = previousProcessedItems.map((previous) => {
return previous.name;
});
definitionsElements = definitionsNames.filter((definitionName) => {
return namesPreviousProcessed.includes(definitionName);
}).map((definitionName) => {
return {
...parsedSchema.definitions[definitionName],
name: definitionName,
fullName: `${parsedSchema.$id}#/definitions/${definitionName}`
};
});
return definitionsElements;
}
/**
* Get the min occurs of an element
* always returns an array
* @param {object} schemaElement the parsed schema element from a WSDL File
* @param {string} fieldName the name of the field to look up
* @returns {string} the value of the min occurs if there is no value then returns 1
*/
getMinOccursOfElement(schemaElement, fieldName) {
if (schemaElement.required) {
return schemaElement.required.includes(fieldName) ? '1' : '0';
}
return '1';
}
/**
* Get the max occurs of an element
* always returns an array
* @param {object} schemaElement the parsed schema element from a WSDL File
* @param {string} fieldName the name of the field to look up
* @returns {string} the value of the min occurs if there is no value then returns 1
*/
getMaxOccursOfElement(schemaElement, fieldName) {
if (schemaElement && fieldName !== '') {
return '1';
}
return '1';
}
/**
* Creates recursively the children nodes of an element
* Assign children and if a complex type is found then
* call itself
* @param {object} rootElement the wsdl element to traverse
* @param {Element} wsdlElement the string name of the type
* @param {Array} processedElements the already processed elements
* @param {string} targetNamespace the target namespace of the element
* @returns {object} assigns elements to object
*/
getChildren(rootElement, wsdlElement, processedElements, targetNamespace) {
let children = [];
wsdlElement.children = children;
traverseUtility(rootElement).forEach((property) => {
if (property) {
let properties = property.properties;
if (properties) {
let keys = Object.keys(properties);
keys.forEach((key) => {
if (properties[key]) {
let hasRef,
type,
oneOfOrAnyOf = Object.keys(properties[key])
.find(
(key) => {
return key === oneOfIdentifier || key === anyOfIdentifier;
}
);
if (!properties[key][oneOfOrAnyOf]) {
oneOfOrAnyOf = undefined;
}
if (key === oneOfIdentifier || key === anyOfIdentifier) {
type += ' ';
}
hasRef = properties[key] ? properties[key].$ref : undefined;
type = oneOfOrAnyOf ? properties[key][oneOfOrAnyOf][0].type : properties[key].type;
if (this.isScalarType(type, hasRef)) {
let element = this.getChildScalarType(key, properties, property, targetNamespace, wsdlElement);
children.push(element);
wsdlElement.children = children;
}
else if (this.isComplexType(properties, key, hasRef)) {
if (!this.hasCircularRefOneLevel(property.properties[key], rootElement.name ?
rootElement.name : rootElement.complexName, this.isSelfReferenceElementLocalNameComparer)) {
this.assignChildComplex(properties, key, wsdlElement, processedElements, property,
targetNamespace);
}
else {
property.properties[key] = {};
}
}
}
});
}
}
});
}
/**
* identifies if the element is scalar e.g. integer string and so on
* according to its type if has a named reference and if it is a known type
* @param {string} type type to find
* @param {string} hasRef if the element has a named reference
* @returns {boolean} true if found it as scalar
*/
isScalarType(type, hasRef) {
return type !== 'object' && !hasRef && isKnownType(type);
}
/**
* identifies if the element is complex e.g. simple types complex types and elements
* of the wsdl.
* according to its type if has a named reference
* @param {object} properties object properties of the json schema
* @param {key} key the property field to check
* @param {string} hasRef if the element has a named reference
* @returns {boolean} true if found it as complex
*/
isComplexType(properties, key, hasRef) {
return properties[key].type === 'object' || hasRef || properties[key].properties;
}
/**
* creates a wsdl element with its scalar type
* @param {key} key the property field to check
* @param {object} properties object properties of the json schema
* @param {object} property if the element has a named reference
* @param {string} targetNamespace the target namespace of the element
* @param {object} parentWsdlElement parent wsdl element
* @returns {WsdlElement} the created element
*/
getChildScalarType(key, properties, property, targetNamespace, parentWsdlElement) {
let element = new Element(),
propertiesObject = this.getTypeFromScalarType(properties[key]);
element.name = key;
element.type = propertiesObject.type;
element.minimum = propertiesObject.minimum;
element.maximum = propertiesObject.maximum;
element.maxLength = propertiesObject.maxLength;
element.minLength = propertiesObject.minLength;
element.pattern = propertiesObject.pattern;
element.contentEncoding = propertiesObject.contentEncoding;
element.enum = propertiesObject.enum;
element.isComplex = false;
element.children = [];
element.minOccurs = this.getMinOccursOfElement(property, key);
element.maxOccurs = this.getMaxOccursOfElement(property, key);
element.namespace = targetNamespace;
// inherit schema attributes from parent wsdl element
element.attributeFormDefault = parentWsdlElement.attributeFormDefault;
element.elementFormDefault = parentWsdlElement.elementFormDefault;
element.nsPrefix = parentWsdlElement.nsPrefix;
return element;
}
getTypeFromScalarType(propertyObject) {
if (propertyObject[oneOfIdentifier]) {
return propertyObject[oneOfIdentifier][0];
}
else if (propertyObject[anyOfIdentifier]) {
return propertyObject[anyOfIdentifier][0];
}
return propertyObject;
}
/**
* creates a wsdl element from a wsdl element type
* @param {key} key the property field to check
* @param {object} properties object properties of the json schema
* @param {object} property if the element has a named reference
* @param {Array} preprocessed preprocessed elements to look for
* @param {string} targetNamespace the target namespace of the element
* @param {object} parentWsdlElement parent wsdl element
* @returns {WsdlElement} the created element
*/
getChildElement(key, properties, property, preprocessed, targetNamespace, parentWsdlElement) {
let element = new Element();
element.name = key;
element.type = properties[key].complexName;
element.isComplex = true;
element.minOccurs = this.getMinOccursOfElement(property, key);
element.maxOccurs = this.getMaxOccursOfElement(property, key);
element.namespace = targetNamespace;
element.children = [];
element.isElement = true;
// inherit schema attributes from parent wsdl element
element.attributeFormDefault = parentWsdlElement.attributeFormDefault;
element.elementFormDefault = parentWsdlElement.elementFormDefault;
element.nsPrefix = parentWsdlElement.nsPrefix;
if (preprocessed.children) {
element.children = preprocessed.children.concat([]);
}
return element;
}
/**
* creates and assigns a wsdl element from a wsdl simple complex or element
* @param {object} properties object properties of the json schema
* @param {string} key the property field to check
* @param {WsdlElement} wsdlElement the parent element
* @param {object} processedElements preprocessed elements
* @param {object} property if the element has a named reference
* @param {string} targetNamespace the target namespace of the element
* @returns {WsdlElement} the created element
*/
assignChildComplex(properties, key, wsdlElement, processedElements, property,
targetNamespace) {
let element = new Element();
if (properties[key].type === ERROR_ELEMENT_IDENTIFIER) {
element = createErrorElement(properties[key], key);
wsdlElement.children.push(element);
}
else {
let preprocessed = this.findIfPreviousProcessedElement(processedElements, properties, key);
if (!preprocessed) {
element.name = key;
element.type = this.getComplexElementType(properties[key]);
element.isComplex = true;
element.minOccurs = this.getMinOccursOfElement(property, key);
element.maxOccurs = this.getMaxOccursOfElement(property, key);
// inherit schema attributes from parent wsdl element
element.attributeFormDefault = wsdlElement.attributeFormDefault;
element.elementFormDefault = wsdlElement.elementFormDefault;
element.nsPrefix = wsdlElement.nsPrefix;
wsdlElement.children.push(element);
if (property.properties[key].properties) {
this.getChildren(property.properties[key], element, processedElements,
targetNamespace);
property.properties[key] = {};
}
}
else if (preprocessed.isElement) {
element = this.getChildElement(key, properties, property, preprocessed,
targetNamespace, wsdlElement);
wsdlElement.children.push(element);
property.properties[key] = {};
}
else {
wsdlElement.children.push(preprocessed);
}
}
}
getComplexElementType(element) {
if (element.complexName) {
return element.complexName;
}
else if (element.$ref) {
let typeFromReference = element.$ref.split('/').reverse()[0];
return typeFromReference.includes(XML_NAMESPACE_SEPARATOR) ?
typeFromReference.split(XML_NAMESPACE_SEPARATOR).reverse()[0] :
typeFromReference;
}
}
/**
* Finds an element if this was previously processed
* @param {Array} preProcessedElements the elements that are
* already processed
* @param {string} properties schema properties
* @param {string} key the elements name
* @returns {element} assigns elements to object
*/
findIfPreviousProcessedElement(preProcessedElements, properties, key) {
let name;
if (properties[key].complexName) {
name = properties[key].complexName;
}
else if (properties[key].$ref) {
name = properties[key].$ref.replace(DEFINITIONS_FILTER, '');
}
else {
name = properties[key].name;
}
if (!preProcessedElements) {
return;
}
const element = preProcessedElements.find((current) => {
return current.name === name;
});
return element;
}
/**
* Gets the type of the element if not found then
* is treated as complex
* @param {element} element the string name of the type
* @returns {string} assigns elements to object
*/
getTypeOfElement(element) {
return element.type === 'object' ? 'complex' : element.type;
}
/**
* Get the complex types from the schema
* always returns an array
* @param {object} schemaTag the binding operation object
* @param {string} schemaPrefix the schema namespace prefix
* @returns {[object]} complex types from the wsdl
*/
getComplexTypesFromSchema(schemaTag, schemaPrefix) {
return getArrayFrom(schemaTag[schemaPrefix + COMPLEX_TYPE_TAG]);
}
/**
* Get the group types from the schema
* always returns an array
* @param {object} schemaTag the binding operation object
* @param {string} schemaPrefix the schema namespace prefix
* @returns {[object]} group types from the wsdl
*/
getGroupsFromSchema(schemaTag, schemaPrefix) {
return getArrayFrom(schemaTag[schemaPrefix + GROUP_TAG]);
}
/**
* Get the attribute types from the schema
* always returns an array
* @param {object} schemaTag the binding operation object
* @param {string} schemaPrefix the schema namespace prefix
* @returns {[object]} attribute types from the wsdl
*/
getGlobalAttributesFromSchema(schemaTag, schemaPrefix) {
return getArrayFrom(schemaTag[schemaPrefix + ATTRIBUTE_TYPE_TAG]);
}
/**
* Get the simple types from the schema
* always returns an array
* @param {object} schemaTag the binding operation object
* @param {string} schemaPrefix the schema namespace prefix
* @returns {[object]} simple types from the wsdl
*/
getSimpleTypesFromSchema(schemaTag, schemaPrefix) {
return getArrayFrom(schemaTag[schemaPrefix + SIMPLE_TYPE_TAG]);
}
/**
* Get the simple types from the schema
* always returns an array
* @param {object} schemaTag the binding operation object
* @param {string} schemaPrefix the schema namespace prefix
* @returns {[object]} simple types from the wsdl
*/
getElementsFromSchema(schemaTag, schemaPrefix) {
return getArrayFrom(schemaTag[schemaPrefix + 'element']);
}
/**
* Get the types of the document