wrekenfile-converter 2.0.3 → 2.0.6

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.
package/README.md CHANGED
@@ -77,49 +77,79 @@ const variables = {}; // Optionally provide Postman environment variables
77
77
  const wrekenfileYaml = generateWrekenfileFromPostman(collection, variables);
78
78
  ```
79
79
 
80
- ---
80
+ ### Validate a Wrekenfile
81
81
 
82
- ## CLI: Convert Postman Collection to Wrekenfile (Local/Dev Only)
82
+ ```typescript
83
+ import { validateWrekenfile } from 'wrekenfile-converter';
83
84
 
84
- A standalone CLI script is provided for local development to convert a Postman collection JSON to a Wrekenfile YAML file. This script is **not included in the published library** and is safe to use only in your own repo.
85
+ const result = validateWrekenfile('./Wrekenfile.yaml');
86
+ console.log(result.isValid ? '✅ Valid' : '❌ Invalid');
87
+ console.log(result.errors, result.warnings);
88
+ ```
85
89
 
86
- **Usage:**
90
+ ### Generate Mini Wrekenfiles
87
91
 
88
- ```bash
89
- npx ts-node src/cli/cli-postman-to-wrekenfile.ts <postman_collection.json> <output_wrekenfile.yaml> [postman_environment.json]
92
+ ```typescript
93
+ import { generateMiniWrekenfiles, MiniWrekenfile } from 'wrekenfile-converter';
94
+
95
+ const miniFiles: MiniWrekenfile[] = generateMiniWrekenfiles('./Wrekenfile.yaml');
96
+ // Each miniFile contains { content, metadata }
90
97
  ```
91
98
 
92
- Real example
99
+ ## CLI Tools
93
100
 
94
- ```
95
- npx ts-node src/cli/cli-postman-to-wrekenfile.ts examples/transact_bridge_postman.json wrekenfile.yaml
101
+ ### Convert OpenAPI to Wrekenfile
102
+
103
+ Generate a Wrekenfile YAML from an OpenAPI (YAML or JSON) spec:
104
+
105
+ ```bash
106
+ npx ts-node src/cli/cli-openapi-to-wrekenfile.ts --input <openapi.yaml|json> [--output <wrekenfile.yaml>] [--cwd <dir>]
96
107
  ```
97
108
 
98
- - The third argument (environment file) is optional.
99
- - Prints helpful usage and error messages.
100
- - Does not affect library builds or usage as a dependency.
109
+ **Options:**
110
+ - `--input` or `-i`: Path to your OpenAPI YAML or JSON file (required)
111
+ - `--output` or `-o`: Path to output Wrekenfile YAML (optional, defaults to `output_wrekenfile.yaml`)
112
+ - `--cwd`: Working directory for resolving $refs (optional, defaults to the input file's directory)
101
113
 
102
- ---
114
+ **Example:**
115
+ ```bash
116
+ npx ts-node src/cli/cli-openapi-to-wrekenfile.ts --input examples/p3id_swagger.json --output wrekenfile.yaml --cwd .
117
+ ```
103
118
 
104
- ### Validate a Wrekenfile
119
+ ### Convert Postman Collection to Wrekenfile
105
120
 
106
- ```typescript
107
- import { validateWrekenfile } from 'wrekenfile-converter';
121
+ Convert a Postman collection JSON to a Wrekenfile YAML file:
108
122
 
109
- const result = validateWrekenfile('./Wrekenfile.yaml');
110
- console.log(result.isValid ? '✅ Valid' : '❌ Invalid');
111
- console.log(result.errors, result.warnings);
123
+ ```bash
124
+ npx ts-node src/cli/cli-postman-to-wrekenfile.ts <postman_collection.json> <output_wrekenfile.yaml> [postman_environment.json]
112
125
  ```
113
126
 
127
+ **Example:**
128
+ ```bash
129
+ npx ts-node src/cli/cli-postman-to-wrekenfile.ts examples/transact_bridge_postman.json wrekenfile.yaml
130
+ ```
131
+
132
+ **Note:** The third argument (environment file) is optional.
133
+
114
134
  ### Generate Mini Wrekenfiles
115
135
 
116
- ```typescript
117
- import { generateMiniWrekenfiles, MiniWrekenfile } from 'wrekenfile-converter';
136
+ Generate mini Wrekenfiles for each endpoint from a main Wrekenfile YAML:
118
137
 
119
- const miniFiles: MiniWrekenfile[] = generateMiniWrekenfiles('./Wrekenfile.yaml');
120
- // Each miniFile contains { content, metadata }
138
+ ```bash
139
+ npx ts-node src/cli/cli-mini-wrekenfile-generator.ts --input <wrekenfile.yaml> [--output <dir>]
140
+ ```
141
+
142
+ **Options:**
143
+ - `--input` or `-i`: Path to your main Wrekenfile YAML (required)
144
+ - `--output` or `-o`: Output directory for mini Wrekenfiles (optional, defaults to `./mini-wrekenfiles`)
145
+
146
+ **Example:**
147
+ ```bash
148
+ npx ts-node src/cli/cli-mini-wrekenfile-generator.ts --input wrekenfile.yaml --output ./mini-wrekenfiles
121
149
  ```
122
150
 
151
+ This will generate one mini Wrekenfile per endpoint in the specified output directory.
152
+
123
153
  ## API Reference
124
154
 
125
155
  ### Core Functions
@@ -191,6 +221,10 @@ src/
191
221
  ├── postman-to-wrekenfile.ts # Postman converter
192
222
  ├── wrekenfile-validator.ts # Validation logic
193
223
  ├── mini-wrekenfile-generator.ts # Mini chunk generator
224
+ ├── cli/ # CLI tools
225
+ │ ├── cli-openapi-to-wrekenfile.ts
226
+ │ ├── cli-postman-to-wrekenfile.ts
227
+ │ └── cli-mini-wrekenfile-generator.ts
194
228
  └── example-usage.ts # Usage examples
195
229
 
196
230
  dist/ # Compiled JavaScript + types
@@ -206,43 +240,4 @@ mini-wrekenfiles/ # Generated mini chunks (if you save them)
206
240
 
207
241
  ## License
208
242
 
209
- MIT
210
-
211
- # Wrekenfile Tools
212
-
213
- ## Generate Wrekenfile from OpenAPI
214
-
215
- You can generate a Wrekenfile YAML from an OpenAPI (YAML or JSON) spec using the CLI:
216
-
217
- ```
218
- npx ts-node src/cli/cli-openapi-to-wrekenfile.ts --input <openapi.yaml|json> [--output <wrekenfile.yaml>] [--cwd <dir>]
219
- ```
220
-
221
- - `--input` or `-i`: Path to your OpenAPI YAML or JSON file (required)
222
- - `--output` or `-o`: Path to output Wrekenfile YAML (optional, defaults to `output_wrekenfile.yaml`)
223
- - `--cwd`: Working directory for resolving $refs (optional, defaults to the input file's directory)
224
-
225
- **Example:**
226
- ```
227
- npx ts-node src/cli/cli-openapi-to-wrekenfile.ts --input examples/p3id_swagger.json --output wrekenfile.yaml --cwd .
228
- ```
229
-
230
- ---
231
-
232
- ## Generate Mini Wrekenfiles from a Wrekenfile
233
-
234
- You can generate mini Wrekenfiles for each endpoint from a main Wrekenfile YAML using the CLI:
235
-
236
- ```
237
- npx ts-node src/cli/cli-mini-wrekenfile-generator.ts --input <wrekenfile.yaml> [--output <dir>]
238
- ```
239
-
240
- - `--input` or `-i`: Path to your main Wrekenfile YAML (required)
241
- - `--output` or `-o`: Output directory for mini Wrekenfiles (optional, defaults to `./mini-wrekenfiles`)
242
-
243
- **Example:**
244
- ```
245
- npx ts-node src/cli/cli-mini-wrekenfile-generator.ts --input wrekenfile.yaml --output ./mini-wrekenfiles
246
- ```
247
-
248
- This will generate one mini Wrekenfile per endpoint in the specified output directory.
243
+ MIT
@@ -256,39 +256,41 @@ function extractStructs(spec, baseDir) {
256
256
  }
257
257
  }
258
258
  // Extract inline schemas from operations
259
- for (const [pathStr, methods] of Object.entries(spec.paths)) {
260
- for (const [method, op] of Object.entries(methods)) {
261
- const operationId = op.operationId || `${method}-${pathStr.replace(/[\/{}]/g, '-')}`;
262
- // Extract request body schemas
263
- if ((_b = op.requestBody) === null || _b === void 0 ? void 0 : _b.content) {
264
- for (const [contentType, content] of Object.entries(op.requestBody.content)) {
265
- if (content && content.schema) {
266
- if (content.schema && content.schema.$ref) {
267
- const refName = content.schema.$ref.split('/').pop();
268
- if (refName)
269
- collectAllReferencedSchemas(resolveRef(content.schema.$ref, spec, baseDir), refName);
270
- }
271
- else if (content.schema && typeof content.schema === 'object') {
272
- const requestStructName = generateStructName(operationId, method, pathStr, 'Request');
273
- collectAllReferencedSchemas(content.schema, requestStructName);
259
+ if (spec.paths && typeof spec.paths === 'object') {
260
+ for (const [pathStr, methods] of Object.entries(spec.paths)) {
261
+ for (const [method, op] of Object.entries(methods)) {
262
+ const operationId = op.operationId || `${method}-${pathStr.replace(/[\/{}]/g, '-')}`;
263
+ // Extract request body schemas
264
+ if ((_b = op.requestBody) === null || _b === void 0 ? void 0 : _b.content) {
265
+ for (const [contentType, content] of Object.entries(op.requestBody.content)) {
266
+ if (content && content.schema) {
267
+ if (content.schema && content.schema.$ref) {
268
+ const refName = content.schema.$ref.split('/').pop();
269
+ if (refName)
270
+ collectAllReferencedSchemas(resolveRef(content.schema.$ref, spec, baseDir), refName);
271
+ }
272
+ else if (content.schema && typeof content.schema === 'object') {
273
+ const requestStructName = generateStructName(operationId, method, pathStr, 'Request');
274
+ collectAllReferencedSchemas(content.schema, requestStructName);
275
+ }
274
276
  }
275
277
  }
276
278
  }
277
- }
278
- // Extract response schemas
279
- if (op.responses) {
280
- for (const [code, response] of Object.entries(op.responses)) {
281
- if (response && response.content) {
282
- for (const [contentType, content] of Object.entries(response.content)) {
283
- if (content && content.schema) {
284
- if (content.schema && content.schema.$ref) {
285
- const refName = content.schema.$ref.split('/').pop();
286
- if (refName)
287
- collectAllReferencedSchemas(resolveRef(content.schema.$ref, spec, baseDir), refName);
288
- }
289
- else if (content.schema && typeof content.schema === 'object') {
290
- const responseStructName = generateStructName(operationId, method, pathStr, `Response${code}`);
291
- collectAllReferencedSchemas(content.schema, responseStructName);
279
+ // Extract response schemas
280
+ if (op.responses) {
281
+ for (const [code, response] of Object.entries(op.responses)) {
282
+ if (response && response.content) {
283
+ for (const [contentType, content] of Object.entries(response.content)) {
284
+ if (content && content.schema) {
285
+ if (content.schema && content.schema.$ref) {
286
+ const refName = content.schema.$ref.split('/').pop();
287
+ if (refName)
288
+ collectAllReferencedSchemas(resolveRef(content.schema.$ref, spec, baseDir), refName);
289
+ }
290
+ else if (content.schema && typeof content.schema === 'object') {
291
+ const responseStructName = generateStructName(operationId, method, pathStr, `Response${code}`);
292
+ collectAllReferencedSchemas(content.schema, responseStructName);
293
+ }
292
294
  }
293
295
  }
294
296
  }
@@ -488,6 +490,11 @@ function extractInterfaces(spec, baseDir) {
488
490
  const interfaces = {};
489
491
  // Valid HTTP methods
490
492
  const validMethods = ['get', 'post', 'put', 'delete', 'patch', 'head', 'options', 'trace'];
493
+ // Check if paths exists and is an object
494
+ if (!spec.paths || typeof spec.paths !== 'object') {
495
+ console.warn('Warning: No paths found in OpenAPI specification');
496
+ return interfaces;
497
+ }
491
498
  for (const [pathStr, methods] of Object.entries(spec.paths)) {
492
499
  for (const [method, op] of Object.entries(methods)) {
493
500
  // Skip extension fields (x-*) and only process valid HTTP methods
@@ -427,8 +427,8 @@ function extractInterfaces(spec) {
427
427
  const returns = extractResponses(op, operationId, method, pathStr);
428
428
  interfaces[alias] = {
429
429
  SUMMARY: op.summary || '',
430
- DESCRIPTION: op.description || '',
431
430
  DESC: generateDesc(op, method, pathStr),
431
+ TAGS: Array.isArray(op.tags) ? op.tags : [],
432
432
  ENDPOINT: endpoint,
433
433
  VISIBILITY: visibility,
434
434
  HTTP: {
@@ -70,11 +70,23 @@ function mapType(value) {
70
70
  return 'ANY';
71
71
  return 'ANY';
72
72
  }
73
+ function getItemDescription(item) {
74
+ var _a, _b, _c, _d, _e;
75
+ let description = (_c = (_a = item === null || item === void 0 ? void 0 : item.description) !== null && _a !== void 0 ? _a : (_b = item === null || item === void 0 ? void 0 : item.request) === null || _b === void 0 ? void 0 : _b.description) !== null && _c !== void 0 ? _c : (_e = (_d = item === null || item === void 0 ? void 0 : item.request) === null || _d === void 0 ? void 0 : _d.body) === null || _e === void 0 ? void 0 : _e.description;
76
+ if (!description)
77
+ return '';
78
+ // Postman can store description as an object with { content: string }
79
+ if (typeof description === 'object' && typeof description.content === 'string') {
80
+ description = description.content;
81
+ }
82
+ if (typeof description !== 'string')
83
+ return '';
84
+ return description.replace(/<[^>]*>/g, '').replace(/\n+/g, ' ').trim();
85
+ }
73
86
  function generateDesc(item, method, path) {
74
- if (item.description) {
75
- // Remove HTML tags and clean up description
76
- return item.description.replace(/<[^>]*>/g, '').replace(/\n+/g, ' ').trim();
77
- }
87
+ const cleaned = getItemDescription(item);
88
+ if (cleaned)
89
+ return cleaned;
78
90
  return `${method.toUpperCase()} ${path}`;
79
91
  }
80
92
  function generateStructName(itemName, method, path, suffix) {
@@ -423,12 +435,13 @@ function extractOperations(collection, variables) {
423
435
  return `${name} ${operationNameCount[name]}`;
424
436
  }
425
437
  }
426
- function processItem(item) {
438
+ function processItem(item, parentName = null) {
427
439
  if (item.request) {
428
440
  const method = item.request.method || 'GET';
429
441
  const url = item.request.url;
430
442
  const path = extractPathFromUrl(url, variables);
431
443
  const itemName = item.name || 'unknown';
444
+ const immediateParentName = parentName || null;
432
445
  // Generate operation ID
433
446
  let operationId = itemName.toLowerCase().replace(/[^a-z0-9]/g, '-');
434
447
  operationId = getUniqueOperationName(operationId);
@@ -444,8 +457,8 @@ function extractOperations(collection, variables) {
444
457
  operations.push({
445
458
  name: operationId,
446
459
  SUMMARY: itemName || '',
447
- DESCRIPTION: item.description ? item.description.replace(/<[^>]*>/g, '').replace(/\n+/g, ' ').trim() : '',
448
460
  DESC: generateDesc(item, method, path),
461
+ TAGS: immediateParentName ? [immediateParentName] : (itemName ? [itemName] : []),
449
462
  ENDPOINT: `"/${path}"`,
450
463
  VISIBILITY: 'PUBLIC',
451
464
  HTTP: {
@@ -459,12 +472,12 @@ function extractOperations(collection, variables) {
459
472
  }
460
473
  if (item.item) {
461
474
  for (const subItem of item.item) {
462
- processItem(subItem);
475
+ processItem(subItem, item.name || parentName || null);
463
476
  }
464
477
  }
465
478
  }
466
479
  for (const item of collection.item) {
467
- processItem(item);
480
+ processItem(item, null);
468
481
  }
469
482
  return operations;
470
483
  }
@@ -531,9 +544,24 @@ function generateWrekenfile(collection, variables) {
531
544
  wrekenfile += `INTERFACES:\n`;
532
545
  for (const operation of operations) {
533
546
  wrekenfile += ` ${operation.name}:\n`;
534
- wrekenfile += ` SUMMARY: ${operation.SUMMARY}\n`;
535
- wrekenfile += ` DESCRIPTION: ${operation.DESCRIPTION}\n`;
536
- wrekenfile += ` DESC: ${operation.DESC}\n`;
547
+ // Quote SUMMARY and DESC if they contain special characters
548
+ const summary = operation.SUMMARY.includes(':') || operation.SUMMARY.includes('"') ? `"${operation.SUMMARY.replace(/"/g, '\\"')}"` : operation.SUMMARY;
549
+ const desc = operation.DESC.includes(':') || operation.DESC.includes('"') ? `"${operation.DESC.replace(/"/g, '\\"')}"` : operation.DESC;
550
+ wrekenfile += ` SUMMARY: ${summary}\n`;
551
+ wrekenfile += ` DESC: ${desc}\n`;
552
+ // TAGS
553
+ if (!operation.TAGS || operation.TAGS.length === 0) {
554
+ wrekenfile += ` TAGS: []\n`;
555
+ }
556
+ else {
557
+ wrekenfile += ` TAGS:\n`;
558
+ for (const tag of operation.TAGS) {
559
+ const tagVal = (typeof tag === 'string' && (tag.includes(':') || tag.includes('"')))
560
+ ? `"${String(tag).replace(/"/g, '\\"')}"`
561
+ : String(tag);
562
+ wrekenfile += ` - ${tagVal}\n`;
563
+ }
564
+ }
537
565
  wrekenfile += ` ENDPOINT: ${operation.ENDPOINT}\n`;
538
566
  wrekenfile += ` VISIBILITY: ${operation.VISIBILITY}\n`;
539
567
  wrekenfile += ` HTTP:\n`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wrekenfile-converter",
3
- "version": "2.0.3",
3
+ "version": "2.0.6",
4
4
  "description": "Convert OpenAPI and Postman specs to Wrekenfile format with mini-chunking for vector DB storage",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",