UNPKG

@darkonig/wsdl-tsclient

Version:

Generate typescript soap client with typescript definitons from WSDL file.

493 lines 27.6 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseWsdl = void 0; var path = __importStar(require("path")); var elements_1 = require("soap/lib/wsdl/elements"); var index_1 = require("soap/lib/wsdl/index"); var parsed_wsdl_1 = require("./models/parsed-wsdl"); var change_case_1 = require("./utils/change-case"); var file_1 = require("./utils/file"); var javascript_1 = require("./utils/javascript"); var logger_1 = require("./utils/logger"); var defaultOptions = { modelNamePreffix: "", modelNameSuffix: "", maxRecursiveDefinitionName: 64, generateAttributes: false, }; function findReferenceDefiniton(visited, definitionParts) { return visited.find(function (def) { return def.parts === definitionParts; }); } /** * parse definition * @param parsedWsdl context of parsed wsdl * @param name name of definition, will be used as name of interface * @param defParts definition's parts - its properties * @param stack definitions stack of path to current subdefinition (immutable) * @param visitedDefs set of globally visited definitions to avoid circular definitions */ function parseDefinition(parsedWsdl, options, name, defParts, stack, visitedDefs, wsdlElementDef, rootWsdlDefinitions) { var defName = (0, change_case_1.changeCase)(name, { pascalCase: true }); logger_1.Logger.debug("Parsing Definition ".concat(stack.join("."), ".").concat(name)); var nonCollisionDefName; try { nonCollisionDefName = parsedWsdl.findNonCollisionDefinitionName(defName); } catch (err) { var e = new Error("Error for finding non-collision definition name for ".concat(stack.join("."), ".").concat(name)); e.stack.split("\n").slice(0, 2).join("\n") + "\n" + err.stack; throw e; } var definition = { name: "".concat(options.modelNamePreffix).concat((0, change_case_1.changeCase)(nonCollisionDefName, { pascalCase: true })).concat(options.modelNameSuffix), sourceName: name, docs: [name], properties: [], description: "", }; parsedWsdl.definitions.push(definition); // Must be here to avoid name collision with `findNonCollisionDefinitionName` if sub-definition has same name visitedDefs.push({ name: definition.name, parts: defParts, definition: definition }); // NOTE: cache reference to this defintion globally (for avoiding circular references) if (options.generateAttributes) { getDefinitionAttributes(options, definition, wsdlElementDef); } if (defParts) { // NOTE: `node-soap` has sometimes problem with parsing wsdl files, it includes `defParts.undefined = undefined` if ("undefined" in defParts && defParts.undefined === undefined) { // TODO: problem while parsing WSDL, maybe report to node-soap // TODO: add flag --FailOnWsdlError logger_1.Logger.error({ message: "Problem while generating a definition file", path: stack.join("."), parts: defParts, }); } else { Object.entries(defParts).forEach(function (_a) { var propName = _a[0], type = _a[1]; var stripedPropName = propName; if (propName === "targetNSAlias") { definition.docs.push("@targetNSAlias `".concat(type, "`")); stripedPropName = null; } else if (propName === "targetNamespace") { definition.docs.push("@targetNamespace `".concat(type, "`")); stripedPropName = null; } else if (propName.endsWith("[]")) { stripedPropName = propName.substring(0, propName.length - 2); // Array of if (typeof type === "string") { // primitive type definition.properties.push({ kind: "PRIMITIVE", name: stripedPropName, sourceName: propName, description: type, type: "string", isArray: true, }); } else if (type instanceof elements_1.ComplexTypeElement) { // TODO: Finish complex type parsing by updating node-soap definition.properties.push({ kind: "PRIMITIVE", name: stripedPropName, sourceName: propName, description: "ComplexType are not supported yet", type: "any", isArray: true, }); logger_1.Logger.warn("Cannot parse ComplexType '".concat(stack.join("."), ".").concat(name, "' - using 'any' type")); } else { // With sub-type var visited = findReferenceDefiniton(visitedDefs, type); if (visited) { // By referencing already declared definition, we will avoid circular references definition.properties.push({ kind: "REFERENCE", name: stripedPropName, sourceName: propName, ref: visited.definition, isArray: true, }); stripedPropName = null; } else { try { var subWsdlElement = wsdlElementDef ? findWsdlElement(stripedPropName, wsdlElementDef, rootWsdlDefinitions) : undefined; var subDefinition = parseDefinition(parsedWsdl, options, stripedPropName, type, __spreadArray(__spreadArray([], stack, true), [propName], false), visitedDefs, subWsdlElement, rootWsdlDefinitions); definition.properties.push({ kind: "REFERENCE", name: stripedPropName, sourceName: propName, ref: subDefinition, isArray: true, }); } catch (err) { var e = new Error("Error while parsing Subdefinition for '".concat(stack.join("."), ".").concat(name, "'")); e.stack.split("\n").slice(0, 2).join("\n") + "\n" + err.stack; throw e; } } } } else { if (typeof type === "string") { // primitive type definition.properties.push({ kind: "PRIMITIVE", name: propName, sourceName: propName, description: type, type: "string", isArray: false, }); } else if (type instanceof elements_1.ComplexTypeElement) { // TODO: Finish complex type parsing by updating node-soap definition.properties.push({ kind: "PRIMITIVE", name: propName, sourceName: propName, description: "ComplexType are not supported yet", type: "any", isArray: false, }); logger_1.Logger.warn("Cannot parse ComplexType '".concat(stack.join("."), ".").concat(name, "' - using 'any' type")); } else { // With sub-type var reference = findReferenceDefiniton(visitedDefs, type); if (reference) { // By referencing already declared definition, we will avoid circular references definition.properties.push({ kind: "REFERENCE", name: propName, sourceName: propName, description: "", ref: reference.definition, isArray: false, }); } else { try { var subWsdlElement = wsdlElementDef ? findWsdlElement(propName, wsdlElementDef, rootWsdlDefinitions) : undefined; var subDefinition = parseDefinition(parsedWsdl, options, propName, type, __spreadArray(__spreadArray([], stack, true), [propName], false), visitedDefs, subWsdlElement, rootWsdlDefinitions); definition.properties.push({ kind: "REFERENCE", name: propName, sourceName: propName, ref: subDefinition, isArray: false, }); } catch (err) { var e = new Error("Error while parsing Subdefinition for ".concat(stack.join("."), ".").concat(name)); e.stack.split("\n").slice(0, 2).join("\n") + "\n" + err.stack; throw e; } } } } }); } } else { // Empty } return definition; } function findWsdlElement(propName, wsdlElementDef, rootWsdlDefinitions) { var _loop_1 = function (element) { if (element.$name === propName) { if (element instanceof elements_1.ElementElement) { if ("$type" in element) { var elementType_1 = element.$type.split(":")[1]; var elementTypeDef = Object.entries(rootWsdlDefinitions.complexTypes).find(function (_a) { var key = _a[0], _ = _a[1]; return key === elementType_1; }); if (elementTypeDef) { return { value: elementTypeDef[1] }; } } return { value: element }; } return { value: undefined }; } if ("children" in element) { var refElement = findWsdlElement(propName, element, rootWsdlDefinitions); if (refElement) { return { value: refElement }; } } }; for (var _i = 0, _a = wsdlElementDef.children; _i < _a.length; _i++) { var element = _a[_i]; var state_1 = _loop_1(element); if (typeof state_1 === "object") return state_1.value; } return undefined; } function findWsdlElementAttributes(wsdlElementDef) { if (!wsdlElementDef) { return []; } return __spreadArray(__spreadArray([], wsdlElementDef.children.filter(function (element) { return element.name === "attribute"; }), true), wsdlElementDef.children .filter(function (el) { return el instanceof elements_1.ComplexTypeElement; }) .flatMap(function (el) { return el.children; }) .filter(function (element) { return element.name === "attribute"; }), true).filter(Boolean); } function getDefinitionAttributes(options, definition, wsdlElementDef) { var stripedPropName = definition.name; var elementAttributes = findWsdlElementAttributes(wsdlElementDef); if (elementAttributes && elementAttributes.length) { var allowedTypes_1 = { string: "string", boolean: "boolean", decimal: "number", any: "any" }; var ignoreAttributes_1 = ["new", "type", "const", "var", "let"]; var name_1 = "attributes"; var subAttrDefinition_1 = { name: "".concat(options.modelNamePreffix).concat((0, change_case_1.changeCase)(stripedPropName, { pascalCase: true })).concat(options.modelNameSuffix, "Attributes"), sourceName: name_1, docs: ["".concat(stripedPropName, " ").concat(name_1)], properties: [], description: "", }; elementAttributes .filter(function (attribute) { return !ignoreAttributes_1.includes(attribute.$name); }) .map(function (attribute) { var _a; var originalType = (_a = attribute === null || attribute === void 0 ? void 0 : attribute.$type) !== null && _a !== void 0 ? _a : "xs:undefined"; var type = originalType.split(":")[1]; subAttrDefinition_1.properties.push({ kind: "PRIMITIVE", name: attribute.$name, sourceName: stripedPropName, description: originalType, type: type in allowedTypes_1 ? allowedTypes_1[type] : "any", isArray: false, }); }); console.debug("Parsing attributes for", stripedPropName, subAttrDefinition_1); definition.properties.push({ kind: "REFERENCE", name: name_1, sourceName: subAttrDefinition_1.name, ref: subAttrDefinition_1, isArray: false, }); return subAttrDefinition_1; } return undefined; } // TODO: Add logs // TODO: Add comments for services, ports, methods and client /** * Parse WSDL to domain model `ParsedWsdl` * @param wsdlPath - path or url to wsdl file */ function parseWsdl(wsdlPath, options) { return __awaiter(this, void 0, void 0, function () { var mergedOptions; return __generator(this, function (_a) { mergedOptions = __assign(__assign({}, defaultOptions), options); return [2 /*return*/, new Promise(function (resolve, reject) { (0, index_1.open_wsdl)(wsdlPath, { namespaceArrayElements: false, ignoredNamespaces: ["tns", "targetNamespace", "typeNamespace"] }, function (err, wsdl) { var _a, _b, _c; if (err) { return reject(err); } if (wsdl === undefined) { return reject(new Error("WSDL is undefined")); } var parsedWsdl = new parsed_wsdl_1.ParsedWsdl({ maxStack: options.maxRecursiveDefinitionName }); var filename = path.basename(wsdlPath); parsedWsdl.name = (0, change_case_1.changeCase)((0, file_1.stripExtension)(filename), { pascalCase: true, }); parsedWsdl.wsdlFilename = path.basename(filename); parsedWsdl.wsdlPath = path.resolve(wsdlPath); var visitedDefinitions = []; var allMethods = []; var allPorts = []; var services = []; for (var _i = 0, _d = Object.entries(wsdl.definitions.services); _i < _d.length; _i++) { var _e = _d[_i], serviceName = _e[0], service = _e[1]; logger_1.Logger.debug("Parsing Service ".concat(serviceName)); var servicePorts = []; // TODO: Convert to Array for (var _f = 0, _g = Object.entries(service.ports); _f < _g.length; _f++) { var _h = _g[_f], portName = _h[0], port = _h[1]; logger_1.Logger.debug("Parsing Port ".concat(portName)); var portMethods = []; for (var _j = 0, _k = Object.entries(port.binding.methods); _j < _k.length; _j++) { var _l = _k[_j], methodName = _l[0], method = _l[1]; logger_1.Logger.debug("Parsing Method ".concat(methodName)); // TODO: Deduplicate code below by refactoring it to external function. Is it even possible ? var paramName = "request"; var inputDefinition = null; // default type if (method.input) { if (method.input.$name) { paramName = method.input.$name; } var inputMessage = wsdl.definitions.messages[method.input.$name]; var schema = wsdl.definitions.schemas[method.input.targetNamespace]; var wsdlComplexTypeDef = schema === null || schema === void 0 ? void 0 : schema.complexTypes[method.input.$name]; if (inputMessage.element) { // TODO: if `$type` not defined, inline type into function declartion (do not create definition file) - wsimport var typeName = (_a = inputMessage.element.$type) !== null && _a !== void 0 ? _a : inputMessage.element.$name; var type = parsedWsdl.findDefinition((_b = inputMessage.element.$type) !== null && _b !== void 0 ? _b : inputMessage.element.$name); inputDefinition = type ? type : parseDefinition(parsedWsdl, mergedOptions, typeName, inputMessage.parts, [typeName], visitedDefinitions, wsdlComplexTypeDef, schema); } else if (inputMessage.parts) { var type = parsedWsdl.findDefinition(paramName); inputDefinition = type ? type : parseDefinition(parsedWsdl, mergedOptions, paramName, inputMessage.parts, [paramName], visitedDefinitions, wsdlComplexTypeDef, schema); } else { logger_1.Logger.debug("Method '".concat(serviceName, ".").concat(portName, ".").concat(methodName, "' doesn't have any input defined")); } } var outputDefinition = null; // default type, `{}` or `unknown` ? if (method.output) { var outputMessage = wsdl.definitions.messages[method.output.$name]; var schema = wsdl.definitions.schemas[method.output.targetNamespace]; var wsdlComplexTypeDef = schema === null || schema === void 0 ? void 0 : schema.complexTypes[method.output.$name]; if (outputMessage.element) { // TODO: if `$type` not defined, inline type into function declartion (do not create definition file) - wsimport var typeName = (_c = outputMessage.element.$type) !== null && _c !== void 0 ? _c : outputMessage.element.$name; var type = parsedWsdl.findDefinition(typeName); outputDefinition = type ? type : parseDefinition(parsedWsdl, mergedOptions, typeName, outputMessage.parts, [typeName], visitedDefinitions, wsdlComplexTypeDef, schema); } else { var type = parsedWsdl.findDefinition(paramName); outputDefinition = type ? type : parseDefinition(parsedWsdl, mergedOptions, paramName, outputMessage.parts, [paramName], visitedDefinitions, wsdlComplexTypeDef, schema); } } var camelParamName = (0, change_case_1.changeCase)(paramName); var portMethod = { name: methodName, paramName: javascript_1.reservedKeywords.includes(camelParamName) ? "".concat(camelParamName, "Param") : camelParamName, paramDefinition: inputDefinition, returnDefinition: outputDefinition, // TODO: Use string from generated definition files }; portMethods.push(portMethod); allMethods.push(portMethod); } var servicePort = { name: (0, change_case_1.changeCase)(portName, { pascalCase: true }), sourceName: portName, methods: portMethods, }; servicePorts.push(servicePort); allPorts.push(servicePort); } // End of Port cycle services.push({ name: (0, change_case_1.changeCase)(serviceName, { pascalCase: true }), sourceName: serviceName, ports: servicePorts, }); } // End of Service cycle parsedWsdl.services = services; parsedWsdl.ports = allPorts; return resolve(parsedWsdl); }); })]; }); }); } exports.parseWsdl = parseWsdl; //# sourceMappingURL=parser.js.map