UNPKG

@mtranter/wsdl-tsclient

Version:

Generate typescript soap client with typescript definitons from WSDL file.

391 lines 22.2 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 }; 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) { 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 (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]; if (propName === "targetNSAlias") { definition.docs.push("@targetNSAlias `".concat(type, "`")); } else if (propName === "targetNamespace") { definition.docs.push("@targetNamespace `".concat(type, "`")); } else if (propName.endsWith("[]")) { var 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, }); } else { try { var subDefinition = parseDefinition(parsedWsdl, options, stripedPropName, type, __spreadArray(__spreadArray([], stack, true), [propName], false), visitedDefs); 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 subDefinition = parseDefinition(parsedWsdl, options, propName, type, __spreadArray(__spreadArray([], stack, true), [propName], false), visitedDefs); 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 { } return definition; } // 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, 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]; 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); } else if (inputMessage.parts) { var type = parsedWsdl.findDefinition(paramName); inputDefinition = type ? type : parseDefinition(parsedWsdl, mergedOptions, paramName, inputMessage.parts, [paramName], visitedDefinitions); } 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]; 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); } else { var type = parsedWsdl.findDefinition(paramName); outputDefinition = type ? type : parseDefinition(parsedWsdl, mergedOptions, paramName, outputMessage.parts, [paramName], visitedDefinitions); } } 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