@karibulab/wsdl2tsx 0.7.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +25 -4
  2. package/dist/cli.js +185 -100
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -11,7 +11,7 @@ npm install -g @karibulab/wsdl2tsx
11
11
  O usar directamente con `npx`:
12
12
 
13
13
  ```bash
14
- npx @karibulab/wsdl2tsx <wsdl-url> <directorio-salida>
14
+ npx @karibulab/wsdl2tsx <wsdl-url> <directorio-salida> [--operation=<nombre>]
15
15
  ```
16
16
 
17
17
  ## Uso
@@ -19,27 +19,42 @@ npx @karibulab/wsdl2tsx <wsdl-url> <directorio-salida>
19
19
  ### Desde línea de comandos
20
20
 
21
21
  ```bash
22
- wsdl2tsx <ruta-wsdl> <directorio-salida>
22
+ wsdl2tsx <ruta-wsdl> <directorio-salida> [--operation=<nombre>]
23
23
  ```
24
24
 
25
- **Ejemplo:**
25
+ **Ejemplos:**
26
26
 
27
27
  ```bash
28
+ # Generar todas las operaciones
28
29
  wsdl2tsx http://ejemplo.com/servicio?wsdl ./output
29
30
  ```
30
31
 
32
+ ```bash
33
+ # Generar solo una operación específica
34
+ wsdl2tsx http://ejemplo.com/servicio?wsdl ./output --operation=ConsultaCodigoPlan
35
+ ```
36
+
37
+ ```bash
38
+ # Con flag corto
39
+ wsdl2tsx http://ejemplo.com/servicio?wsdl ./output -o ConsultaCodigoPlan
40
+ ```
41
+
31
42
  ### Parámetros
32
43
 
33
44
  - `<ruta-wsdl>`: URL o ruta local al archivo WSDL
34
45
  - `<directorio-salida>`: Directorio donde se generarán los archivos TSX
46
+ - `--operation=<nombre>` o `-o <nombre>` (opcional): Especifica el nombre de la operación a generar. Si no se especifica, se generan todas las operaciones con input definido. El nombre debe coincidir exactamente con el nombre de la operación en el WSDL (no es case-sensitive).
35
47
 
36
48
  ## Características
37
49
 
38
50
  - ✅ Genera componentes TypeScript/TSX tipados desde WSDL
51
+ - ✅ **Soporta múltiples operaciones**: Genera un archivo TSX por cada operación del WSDL
52
+ - ✅ **Filtrado por operación**: Permite generar solo una operación específica con `--operation` o `-o`
39
53
  - ✅ Respeta `elementFormDefault` para manejo correcto de namespaces
40
54
  - ✅ Genera interfaces TypeScript para todos los tipos complejos
41
55
  - ✅ Soporta múltiples schemas y namespaces
42
56
  - ✅ Maneja imports y referencias entre schemas
57
+ - ✅ Omite automáticamente operaciones sin input (notificaciones, solo-output)
43
58
  - ✅ Genera código compatible con el runtime `@karibulab/wsdl2tsx-runtime`
44
59
 
45
60
  ## Ejemplo de salida
@@ -85,9 +100,15 @@ npm run build:cli
85
100
 
86
101
  # Ejecutar localmente
87
102
  cd packages/cli
88
- node dist/cli.js <wsdl-url> <output-dir>
103
+ node dist/cli.js <wsdl-url> <output-dir> [--operation=<nombre>]
89
104
  ```
90
105
 
106
+ ### Notas sobre operaciones
107
+
108
+ - **Operaciones sin input**: Las operaciones que no tienen un nodo `input` definido (como notificaciones o operaciones solo-output) se omiten automáticamente con una advertencia.
109
+ - **Múltiples operaciones**: Por defecto, el CLI procesa todas las operaciones válidas y genera un archivo por cada una.
110
+ - **Filtrado**: Usa `--operation` o `-o` para generar solo una operación específica, útil cuando trabajas con WSDL grandes.
111
+
91
112
  ## Licencia
92
113
 
93
114
  ISC
package/dist/cli.js CHANGED
@@ -22478,9 +22478,14 @@ var getPortTypeNode = (node) => {
22478
22478
  const portTypeField = Object.keys(node).find((objectField) => objectField.match(/([a-zA-z0-9]*:)?portType/));
22479
22479
  return node[portTypeField];
22480
22480
  };
22481
- var getOperationNode = (node) => {
22481
+ var getOperationNodes = (node) => {
22482
22482
  const operationField = Object.keys(node).find((objectField) => objectField.match(/([a-zA-z0-9]*:)?operation/));
22483
- return node[operationField];
22483
+ if (!operationField) return [];
22484
+ const operationValue = node[operationField];
22485
+ return Array.isArray(operationValue) ? operationValue : operationValue ? [operationValue] : [];
22486
+ };
22487
+ var getOperationName = (operationNode) => {
22488
+ return operationNode.name || "UnknownOperation";
22484
22489
  };
22485
22490
  var getInputNode = (node) => {
22486
22491
  const inputField = Object.keys(node).find((objectField) => objectField.match(/([a-zA-z0-9]*:)?input/));
@@ -22490,21 +22495,14 @@ var getPartNode = (node) => {
22490
22495
  const partField = Object.keys(node).find((objectField) => objectField.match(/([a-zA-z0-9]*:)?part/));
22491
22496
  return node[partField];
22492
22497
  };
22493
- var getRequestTypeFromDefinitions = (definitionsNode, schemaObject) => {
22494
- const portTypeNode = getPortTypeNode(definitionsNode);
22495
- if (!portTypeNode) {
22496
- throw new Error("No se encontr\xF3 el nodo portType en las definiciones del WSDL");
22497
- }
22498
- const operationNode = getOperationNode(portTypeNode);
22499
- if (!operationNode) {
22500
- throw new Error("No se encontr\xF3 el nodo operation en el portType");
22501
- }
22498
+ var getRequestTypeFromOperation = (operationNode, definitionsNode, schemaObject) => {
22499
+ const operationName = getOperationName(operationNode);
22502
22500
  const inputNode = getInputNode(operationNode);
22503
22501
  if (!inputNode) {
22504
- throw new Error("No se encontr\xF3 el nodo input en la operaci\xF3n");
22502
+ return null;
22505
22503
  }
22506
22504
  if (!inputNode.message) {
22507
- throw new Error("El nodo input no tiene el atributo message definido");
22505
+ throw new Error(`El nodo input de la operaci\xF3n '${operationName}' no tiene el atributo message definido`);
22508
22506
  }
22509
22507
  const messageNode = getMessageNode(definitionsNode);
22510
22508
  if (!messageNode || messageNode.length === 0) {
@@ -22516,10 +22514,10 @@ var getRequestTypeFromDefinitions = (definitionsNode, schemaObject) => {
22516
22514
  }
22517
22515
  const partNode = getPartNode(inputMessageNode);
22518
22516
  if (!partNode) {
22519
- throw new Error("No se encontr\xF3 el nodo part en el mensaje de entrada");
22517
+ throw new Error(`No se encontr\xF3 el nodo part en el mensaje de entrada de la operaci\xF3n '${operationName}'`);
22520
22518
  }
22521
22519
  if (!partNode.element) {
22522
- throw new Error("El nodo part no tiene el atributo element definido");
22520
+ throw new Error(`El nodo part de la operaci\xF3n '${operationName}' no tiene el atributo element definido`);
22523
22521
  }
22524
22522
  const definitionsNamespaces = getNamespacesFromNode(definitionsNode);
22525
22523
  let elementName = partNode.element;
@@ -22538,10 +22536,10 @@ var getRequestTypeFromDefinitions = (definitionsNode, schemaObject) => {
22538
22536
  if (!requestType) {
22539
22537
  const availableTypes = Object.keys(schemaObject).filter((k) => k !== "$namespace").join(", ");
22540
22538
  throw new Error(
22541
- `No se encontr\xF3 el tipo de solicitud '${partNode.element}' (resuelto: '${resolvedElementName}') en el schema. Tipos disponibles: ${availableTypes || "ninguno"}`
22539
+ `No se encontr\xF3 el tipo de solicitud '${partNode.element}' (resuelto: '${resolvedElementName}') para la operaci\xF3n '${operationName}'. Tipos disponibles: ${availableTypes || "ninguno"}`
22542
22540
  );
22543
22541
  }
22544
- return requestType;
22542
+ return { operationName, requestType };
22545
22543
  };
22546
22544
  var getNamespacesFromNode = (node) => {
22547
22545
  const namespaces = /* @__PURE__ */ new Map();
@@ -23329,7 +23327,7 @@ function compileTemplate(templateData) {
23329
23327
  }
23330
23328
  return compiledTemplate(templateData);
23331
23329
  }
23332
- async function generateTsxFromWsdl(wsdlPath, outDir) {
23330
+ async function generateTsxFromWsdl(wsdlPath, outDir, operationName) {
23333
23331
  const wsdlRoot = await loadXml(wsdlPath);
23334
23332
  const definitionsNode = getDefinitionsNode(wsdlRoot);
23335
23333
  if (!definitionsNode) {
@@ -23411,101 +23409,188 @@ Schema [${i}] (targetNamespace: ${schemaNode.targetNamespace || "no definido"}):
23411
23409
  }
23412
23410
  throw new Error(errorMsg);
23413
23411
  }
23414
- const requestType = getRequestTypeFromDefinitions(definitionsNode, schemaObject);
23415
- if (!requestType) {
23416
- throw new Error("No se pudo determinar el tipo de solicitud desde las definiciones del WSDL");
23417
- }
23418
- const requestTypeObject = schemaObject[requestType];
23419
- if (!requestTypeObject) {
23420
- throw new Error(`No se encontr\xF3 el objeto de tipo ${requestType} en el schema`);
23421
- }
23422
- if (!requestTypeObject["$namespace"] && schemaObject["$namespace"]) {
23423
- requestTypeObject["$namespace"] = schemaObject["$namespace"];
23424
- }
23425
- if (!requestTypeObject["$namespace"]) {
23426
- throw new Error(`El tipo ${requestType} no tiene namespace definido`);
23427
- }
23428
- if (Object.keys(allComplexTypes).length > 0) {
23429
- }
23430
- const allTypesForInterfaces = { ...requestTypeObject };
23431
- const findReferencedTypes = (obj, found = /* @__PURE__ */ new Set(), depth = 0) => {
23432
- const indent = " ".repeat(depth);
23433
- for (const [key, value] of Object.entries(obj)) {
23434
- if (key === "$namespace" || key === "$base") continue;
23435
- if (typeof value === "object" && value !== null && "type" in value) {
23436
- const typeValue = value.type;
23437
- if (typeof typeValue === "string") {
23438
- const matchingType = Object.keys(allComplexTypes).find(
23439
- (k) => k === typeValue || k.endsWith(":" + typeValue.split(":").pop()) || k.split(":").pop() === typeValue.split(":").pop()
23440
- );
23441
- if (matchingType && !found.has(matchingType)) {
23442
- found.add(matchingType);
23443
- if (allComplexTypes[matchingType]) {
23444
- findReferencedTypes(allComplexTypes[matchingType], found, depth + 1);
23412
+ const portTypeNode = getPortTypeNode(definitionsNode);
23413
+ if (!portTypeNode) {
23414
+ throw new Error("No se encontr\xF3 el nodo portType en las definiciones del WSDL");
23415
+ }
23416
+ const operationNodes = getOperationNodes(portTypeNode);
23417
+ if (operationNodes.length === 0) {
23418
+ throw new Error("No se encontraron operaciones en el portType");
23419
+ }
23420
+ const operationsToProcess = operationName ? operationNodes.filter((op) => {
23421
+ const opName = getOperationName(op);
23422
+ return opName === operationName || opName.toLowerCase() === operationName.toLowerCase();
23423
+ }) : operationNodes;
23424
+ if (operationName && operationsToProcess.length === 0) {
23425
+ const availableOps = operationNodes.map((op) => getOperationName(op)).join(", ");
23426
+ throw new Error(
23427
+ `No se encontr\xF3 la operaci\xF3n '${operationName}'. Operaciones disponibles: ${availableOps || "ninguna"}`
23428
+ );
23429
+ }
23430
+ const processOperation = (operationNode) => {
23431
+ const operationInfo = getRequestTypeFromOperation(operationNode, definitionsNode, schemaObject);
23432
+ if (!operationInfo) {
23433
+ const opName2 = getOperationName(operationNode);
23434
+ console.warn(`\u26A0\uFE0F Operaci\xF3n '${opName2}' no tiene input, se omite`);
23435
+ return;
23436
+ }
23437
+ const { operationName: opName, requestType } = operationInfo;
23438
+ const requestTypeObject = schemaObject[requestType];
23439
+ if (!requestTypeObject) {
23440
+ throw new Error(`No se encontr\xF3 el objeto de tipo ${requestType} en el schema para la operaci\xF3n '${opName}'`);
23441
+ }
23442
+ if (!requestTypeObject["$namespace"] && schemaObject["$namespace"]) {
23443
+ requestTypeObject["$namespace"] = schemaObject["$namespace"];
23444
+ }
23445
+ if (!requestTypeObject["$namespace"]) {
23446
+ throw new Error(`El tipo ${requestType} no tiene namespace definido para la operaci\xF3n '${opName}'`);
23447
+ }
23448
+ const allTypesForInterfaces = { ...requestTypeObject };
23449
+ const findReferencedTypes = (obj, found = /* @__PURE__ */ new Set(), depth = 0) => {
23450
+ for (const [key, value] of Object.entries(obj)) {
23451
+ if (key === "$namespace" || key === "$base") continue;
23452
+ if (typeof value === "object" && value !== null && "type" in value) {
23453
+ const typeValue = value.type;
23454
+ if (typeof typeValue === "string") {
23455
+ const matchingType = Object.keys(allComplexTypes).find(
23456
+ (k) => k === typeValue || k.endsWith(":" + typeValue.split(":").pop()) || k.split(":").pop() === typeValue.split(":").pop()
23457
+ );
23458
+ if (matchingType && !found.has(matchingType)) {
23459
+ found.add(matchingType);
23460
+ if (allComplexTypes[matchingType]) {
23461
+ findReferencedTypes(allComplexTypes[matchingType], found, depth + 1);
23462
+ }
23463
+ } else if (matchingType && found.has(matchingType)) {
23445
23464
  }
23446
- } else if (matchingType && found.has(matchingType)) {
23465
+ } else if (typeof typeValue === "object" && typeValue !== null) {
23466
+ findReferencedTypes(typeValue, found, depth + 1);
23447
23467
  }
23448
- } else if (typeof typeValue === "object" && typeValue !== null) {
23449
- findReferencedTypes(typeValue, found, depth + 1);
23450
23468
  }
23451
23469
  }
23452
- }
23453
- return found;
23470
+ return found;
23471
+ };
23472
+ const referencedTypeNames = findReferencedTypes(requestTypeObject);
23473
+ for (const typeName of referencedTypeNames) {
23474
+ if (!allTypesForInterfaces[typeName] && allComplexTypes[typeName]) {
23475
+ allTypesForInterfaces[typeName] = allComplexTypes[typeName];
23476
+ }
23477
+ }
23478
+ for (const [typeName, typeDef] of Object.entries(allComplexTypes)) {
23479
+ if (!allTypesForInterfaces[typeName]) {
23480
+ allTypesForInterfaces[typeName] = typeDef;
23481
+ }
23482
+ }
23483
+ const namespaceMappings = extractAllNamespaceMappings(requestType, requestTypeObject);
23484
+ const namespacesTagsMapping = namespaceMappings.tagsMapping;
23485
+ const namespacesPrefixMapping = namespaceMappings.prefixesMapping;
23486
+ const namespacesTypeMapping = namespaceMappings.typesMapping;
23487
+ const baseNamespacePrefix = namespacesTypeMapping[requestType].prefix;
23488
+ const templateData = prepareTemplateData(
23489
+ requestType,
23490
+ requestTypeObject,
23491
+ // Usar requestTypeObject original para propsInterface
23492
+ namespacesTagsMapping,
23493
+ namespacesPrefixMapping,
23494
+ namespacesTypeMapping,
23495
+ soapNamespaceURI,
23496
+ baseNamespacePrefix,
23497
+ allTypesForInterfaces
23498
+ // Pasar allTypesForInterfaces como parámetro adicional para interfaces
23499
+ );
23500
+ const generatedCode = compileTemplate(templateData);
23501
+ const typeNameForFile = opName;
23502
+ if (!import_fs2.default.existsSync(outDir)) {
23503
+ import_fs2.default.mkdirSync(outDir, { recursive: true });
23504
+ }
23505
+ const outputPath = import_path2.default.join(outDir, `${typeNameForFile}.tsx`);
23506
+ import_fs2.default.writeFileSync(outputPath, generatedCode);
23507
+ console.log(`\u2705 Archivo ${typeNameForFile}.tsx generado correctamente en ${outDir}`);
23454
23508
  };
23455
- const referencedTypeNames = findReferencedTypes(requestTypeObject);
23456
- if (referencedTypeNames.size > 0) {
23457
- }
23458
- for (const typeName of referencedTypeNames) {
23459
- if (!allTypesForInterfaces[typeName] && allComplexTypes[typeName]) {
23460
- allTypesForInterfaces[typeName] = allComplexTypes[typeName];
23461
- }
23462
- }
23463
- for (const [typeName, typeDef] of Object.entries(allComplexTypes)) {
23464
- if (!allTypesForInterfaces[typeName]) {
23465
- allTypesForInterfaces[typeName] = typeDef;
23466
- }
23467
- }
23468
- const namespaceMappings = extractAllNamespaceMappings(requestType, requestTypeObject);
23469
- const namespacesTagsMapping = namespaceMappings.tagsMapping;
23470
- const namespacesPrefixMapping = namespaceMappings.prefixesMapping;
23471
- const namespacesTypeMapping = namespaceMappings.typesMapping;
23472
- const baseNamespacePrefix = namespacesTypeMapping[requestType].prefix;
23473
- const templateData = prepareTemplateData(
23474
- requestType,
23475
- requestTypeObject,
23476
- // Usar requestTypeObject original para propsInterface
23477
- namespacesTagsMapping,
23478
- namespacesPrefixMapping,
23479
- namespacesTypeMapping,
23480
- soapNamespaceURI,
23481
- baseNamespacePrefix,
23482
- allTypesForInterfaces
23483
- // Pasar allTypesForInterfaces como parámetro adicional para interfaces
23484
- );
23485
- if (templateData.interfaces.length > 0) {
23509
+ let generatedCount = 0;
23510
+ for (const operationNode of operationsToProcess) {
23511
+ try {
23512
+ processOperation(operationNode);
23513
+ generatedCount++;
23514
+ } catch (error) {
23515
+ const opName = getOperationName(operationNode);
23516
+ console.error(`\u274C Error al procesar operaci\xF3n '${opName}':`, error.message);
23517
+ if (operationName) {
23518
+ throw error;
23519
+ }
23520
+ }
23486
23521
  }
23487
- const generatedCode = compileTemplate(templateData);
23488
- const typeNameForFile = requestType.includes(":") ? requestType.split(":").pop() : requestType;
23489
- if (!import_fs2.default.existsSync(outDir)) {
23490
- import_fs2.default.mkdirSync(outDir, { recursive: true });
23522
+ if (generatedCount === 0) {
23523
+ throw new Error("No se gener\xF3 ning\xFAn archivo. Verifica que las operaciones tengan input definido.");
23491
23524
  }
23492
- const outputPath = import_path2.default.join(outDir, `${typeNameForFile}.tsx`);
23493
- import_fs2.default.writeFileSync(outputPath, generatedCode);
23494
- console.log(`Archivo ${typeNameForFile}.tsx generado correctamente en ${outDir}`);
23525
+ console.log(`
23526
+ \u2728 Proceso completado: ${generatedCount} archivo(s) generado(s)`);
23495
23527
  }
23496
23528
 
23497
23529
  // src/cli.ts
23498
23530
  console.log("wsdl2tsx CLI - Generador de c\xF3digo TSX desde WSDL");
23499
- var WSDL_PATH = process.argv[2];
23500
- var OUT_DIR = process.argv[3];
23501
- if (!WSDL_PATH || !OUT_DIR) {
23502
- console.error("Uso: tsx cli/generate-tsx.ts <ruta-wsdl> <directorio-salida>");
23503
- process.exit(1);
23531
+ function parseArgs() {
23532
+ const args = process.argv.slice(2);
23533
+ let wsdlPath;
23534
+ let outDir;
23535
+ let operationName;
23536
+ for (let i = 0; i < args.length; i++) {
23537
+ const arg = args[i];
23538
+ if (arg === "--operation" || arg === "-o") {
23539
+ if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
23540
+ const value = args[i + 1];
23541
+ if (!value || value.trim() === "") {
23542
+ throw new Error(`El flag ${arg} requiere un valor no vac\xEDo`);
23543
+ }
23544
+ operationName = value;
23545
+ i++;
23546
+ } else {
23547
+ throw new Error(`El flag ${arg} requiere un valor`);
23548
+ }
23549
+ } else if (arg.startsWith("--operation=")) {
23550
+ const value = arg.split("=")[1];
23551
+ if (!value || value.trim() === "") {
23552
+ throw new Error("El flag --operation requiere un valor no vac\xEDo");
23553
+ }
23554
+ operationName = value;
23555
+ } else if (arg.startsWith("-o=")) {
23556
+ const value = arg.split("=")[1];
23557
+ if (!value || value.trim() === "") {
23558
+ throw new Error("El flag -o requiere un valor no vac\xEDo");
23559
+ }
23560
+ operationName = value;
23561
+ } else if (!wsdlPath) {
23562
+ wsdlPath = arg;
23563
+ } else if (!outDir) {
23564
+ outDir = arg;
23565
+ } else {
23566
+ if (!operationName) {
23567
+ operationName = arg;
23568
+ }
23569
+ }
23570
+ }
23571
+ return { wsdlPath, outDir, operationName };
23504
23572
  }
23505
- generateTsxFromWsdl(WSDL_PATH, OUT_DIR).catch((error) => {
23506
- console.error("Error al generar TSX:", error);
23573
+ try {
23574
+ const { wsdlPath, outDir, operationName } = parseArgs();
23575
+ if (!wsdlPath || !outDir) {
23576
+ console.error("Uso: wsdl2tsx <ruta-wsdl> <directorio-salida> [--operation=<nombre>]");
23577
+ console.error(" --operation, -o: Especifica el nombre de la operaci\xF3n a generar");
23578
+ console.error(" Si no se especifica --operation, se generan todas las operaciones");
23579
+ console.error("");
23580
+ console.error("Ejemplos:");
23581
+ console.error(" wsdl2tsx wsdl.xml output/");
23582
+ console.error(" wsdl2tsx wsdl.xml output/ --operation=Add");
23583
+ console.error(" wsdl2tsx wsdl.xml output/ -o Add");
23584
+ process.exit(1);
23585
+ }
23586
+ generateTsxFromWsdl(wsdlPath, outDir, operationName).catch((error) => {
23587
+ console.error("Error al generar TSX:", error);
23588
+ process.exit(1);
23589
+ });
23590
+ } catch (error) {
23591
+ console.error("Error al parsear argumentos:", error.message);
23507
23592
  process.exit(1);
23508
- });
23593
+ }
23509
23594
  /*! Bundled license information:
23510
23595
 
23511
23596
  mime-db/index.js:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karibulab/wsdl2tsx",
3
- "version": "0.7.0",
3
+ "version": "0.8.1",
4
4
  "description": "Generador de código TSX desde archivos WSDL",
5
5
  "main": "dist/index.js",
6
6
  "bin": "./dist/cli.js",
@@ -13,7 +13,7 @@
13
13
  "start": "node dist/cli.js"
14
14
  },
15
15
  "dependencies": {
16
- "@karibulab/wsdl2tsx-runtime": "0.7.0",
16
+ "@karibulab/wsdl2tsx-runtime": "0.8.1",
17
17
  "axios": "^1.7.9",
18
18
  "fast-xml-parser": "5.3.3",
19
19
  "handlebars": "4.7.8"