#
tokens: 14621/50000 2/51 files (page 2/2)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 2 of 2. Use http://codebase.md/djkz/bruno-api-mcp?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .gitignore
├── babel.config.js
├── coverage
│   ├── clover.xml
│   ├── coverage-final.json
│   ├── lcov-report
│   │   ├── base.css
│   │   ├── block-navigation.js
│   │   ├── favicon.png
│   │   ├── index.html
│   │   ├── prettify.css
│   │   ├── prettify.js
│   │   ├── sort-arrow-sprite.png
│   │   └── sorter.js
│   └── lcov.info
├── examples
│   └── oauth2-integration.ts
├── jest.config.cjs
├── package.json
├── README.md
├── src
│   ├── auth
│   │   ├── adapter.ts
│   │   ├── factory.ts
│   │   ├── handlers
│   │   │   ├── apikey.ts
│   │   │   ├── basic.ts
│   │   │   ├── bearer.ts
│   │   │   └── oauth2.ts
│   │   ├── index.ts
│   │   ├── integration.ts
│   │   ├── service.ts
│   │   ├── token-manager.ts
│   │   └── types.ts
│   ├── bruno-lang
│   │   ├── brulang.d.ts
│   │   ├── brulang.js
│   │   ├── bruToJson.d.ts
│   │   ├── bruToJson.js
│   │   ├── collectionBruToJson.d.ts
│   │   ├── collectionBruToJson.js
│   │   ├── dotenvToJson.js
│   │   ├── envToJson.d.ts
│   │   └── envToJson.js
│   ├── bruno-parser.ts
│   ├── bruno-tools.ts
│   ├── bruno-utils.ts
│   ├── index.ts
│   ├── request-executor.ts
│   ├── types
│   │   └── bru-js.d.ts
│   ├── types.d.ts
│   └── types.ts
├── test
│   ├── auth-module.test.ts
│   ├── bruno-collection.test.ts
│   ├── bruno-env.test.ts
│   ├── bruno-params-docs.test.ts
│   ├── bruno-parser-auth.test.ts
│   ├── bruno-request.test.ts
│   ├── bruno-tools-integration.test.ts
│   ├── bruno-tools.test.ts
│   ├── defaults.spec.ts
│   ├── fixtures
│   │   ├── collection.bru
│   │   ├── collection2.bru
│   │   ├── deal.bru
│   │   ├── deals-list.bru
│   │   ├── direct-auth.bru
│   │   ├── environments
│   │   │   ├── dev.bru
│   │   │   ├── local.bru
│   │   │   └── remote.bru
│   │   ├── json
│   │   │   ├── collection.json
│   │   │   └── self-company.json
│   │   ├── self-company.bru
│   │   ├── user.bru
│   │   └── V2-deals-show.bru
│   ├── oauth2-auth.test.ts
│   ├── parser.test.ts
│   ├── request-executor.test.ts
│   └── token-manager.test.ts
├── tsconfig.json
└── tsconfig.test.json
```

# Files

--------------------------------------------------------------------------------
/src/bruno-parser.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import fs from "fs-extra";
  2 | import * as path from "path";
  3 | import axios from "axios";
  4 | import debug from "debug";
  5 | import {
  6 |   bruToJson,
  7 |   envToJson,
  8 |   collectionBruToJson,
  9 | } from "./bruno-lang/brulang.js";
 10 | import { applyAuthToParsedRequest } from "./auth/index.js";
 11 | 
 12 | const log = debug("bruno-parser");
 13 | const debugReq = debug("bruno-request");
 14 | 
 15 | // Match {{baseUrl}} or any other template variable {{varName}}
 16 | const TEMPLATE_VAR_REGEX = /{{([^}]+)}}/g;
 17 | 
 18 | interface BrunoResponse {
 19 |   status: number;
 20 |   headers: any;
 21 |   data: any;
 22 |   isJson?: boolean;
 23 |   error?: boolean;
 24 | }
 25 | 
 26 | export interface ParsedRequest {
 27 |   name: string;
 28 |   method: string;
 29 |   url: string;
 30 |   rawRequest: any;
 31 |   headers: Record<string, string>;
 32 |   queryParams: Record<string, string>;
 33 |   body?: {
 34 |     type: string;
 35 |     content: any;
 36 |   };
 37 |   filePath?: string;
 38 | }
 39 | 
 40 | export interface EnvironmentData {
 41 |   name: string;
 42 |   variables: Record<string, string>;
 43 |   rawData: any;
 44 | }
 45 | 
 46 | export class BrunoParser {
 47 |   collectionPath: string;
 48 |   basePath: string;
 49 |   envVars: Record<string, string> = {};
 50 |   environment?: string;
 51 |   availableEnvironments: Map<string, EnvironmentData> = new Map();
 52 |   parsedRequests: Map<string, any> = new Map();
 53 |   parsedCollection: any = null;
 54 | 
 55 |   constructor(collectionPath: string, environment?: string) {
 56 |     this.collectionPath = collectionPath;
 57 |     this.basePath = path.dirname(collectionPath);
 58 |     this.environment = environment;
 59 |   }
 60 | 
 61 |   async init() {
 62 |     // Check if the collection path exists
 63 |     try {
 64 |       await fs.access(this.collectionPath);
 65 |     } catch (error: unknown) {
 66 |       throw new Error(`Collection path does not exist: ${this.collectionPath}`);
 67 |     }
 68 | 
 69 |     try {
 70 |       // Load all available environments
 71 |       await this.loadAllEnvironments();
 72 | 
 73 |       // Load the collection
 74 |       try {
 75 |         this.parsedCollection = await this.parseCollection();
 76 |       } catch (error) {
 77 |         log(`Error parsing collection: ${error}`);
 78 |         this.parsedCollection = {
 79 |           meta: { name: "collection", type: "collection" },
 80 |         };
 81 |       }
 82 | 
 83 |       // Load all request files
 84 |       await this.loadAllRequests();
 85 | 
 86 |       // Set the active environment if specified
 87 |       if (this.environment) {
 88 |         this.setEnvironment(this.environment);
 89 |       }
 90 |     } catch (error: unknown) {
 91 |       log(`Error during parser initialization: ${error}`);
 92 |       throw error;
 93 |     }
 94 |   }
 95 | 
 96 |   async loadAllEnvironments() {
 97 |     const envPath = path.join(this.basePath, "environments");
 98 | 
 99 |     try {
100 |       // Check if the environments directory exists
101 |       if (await fs.pathExists(envPath)) {
102 |         const files = await fs.readdir(envPath);
103 |         const envFiles = files.filter(
104 |           (file) => file.endsWith(".env") || file.endsWith(".bru")
105 |         );
106 | 
107 |         // Load all environment files
108 |         for (const envFile of envFiles) {
109 |           const envName = path.basename(
110 |             envFile,
111 |             envFile.endsWith(".bru") ? ".bru" : ".env"
112 |           );
113 |           const envFilePath = path.join(envPath, envFile);
114 |           const envContent = await fs.readFile(envFilePath, "utf-8");
115 | 
116 |           try {
117 |             const envData = envToJson(envContent);
118 |             const variables: Record<string, string> = {};
119 | 
120 |             // Extract variables to our simplified format
121 |             if (envData) {
122 |               if (envData.vars) {
123 |                 // Legacy .env format
124 |                 Object.entries(envData.vars).forEach(([name, value]) => {
125 |                   variables[name] = String(value);
126 |                 });
127 |               } else if (envData.variables) {
128 |                 // New .bru format
129 |                 envData.variables.forEach((variable: any) => {
130 |                   if (variable.enabled && variable.name) {
131 |                     variables[variable.name] = variable.value || "";
132 |                   }
133 |                 });
134 |               }
135 |             }
136 | 
137 |             // Store the environment data
138 |             this.availableEnvironments.set(envName, {
139 |               name: envName,
140 |               variables,
141 |               rawData: envData,
142 |             });
143 |             log(`Environment loaded: ${envName}`);
144 | 
145 |             // If this is the first environment and no specific one was requested,
146 |             // set it as the default
147 |             if (!this.environment && this.availableEnvironments.size === 1) {
148 |               this.environment = envName;
149 |               this.envVars = { ...variables };
150 |               log(`Set default environment: ${envName}`);
151 |             }
152 |           } catch (error: unknown) {
153 |             const errorMessage =
154 |               error instanceof Error ? error.message : String(error);
155 |             log(
156 |               `Error parsing environment file ${envFilePath}: ${errorMessage}`
157 |             );
158 |           }
159 |         }
160 | 
161 |         log(
162 |           "Available environments:",
163 |           Array.from(this.availableEnvironments.keys())
164 |         );
165 |         log("Current environment variables:", this.envVars);
166 |       }
167 |     } catch (error: unknown) {
168 |       const errorMessage =
169 |         error instanceof Error ? error.message : String(error);
170 |       log(`Error loading environments: ${errorMessage}`);
171 |     }
172 |   }
173 | 
174 |   setEnvironment(envName: string): boolean {
175 |     const env = this.availableEnvironments.get(envName);
176 |     if (env) {
177 |       this.environment = envName;
178 |       this.envVars = { ...env.variables };
179 |       log(`Environment set to: ${envName}`);
180 |       return true;
181 |     }
182 |     log(`Environment not found: ${envName}`);
183 |     return false;
184 |   }
185 | 
186 |   getAvailableEnvironments(): string[] {
187 |     return Array.from(this.availableEnvironments.keys());
188 |   }
189 | 
190 |   getEnvironment(envName: string): EnvironmentData | undefined {
191 |     return this.availableEnvironments.get(envName);
192 |   }
193 | 
194 |   getCurrentEnvironment(): EnvironmentData | undefined {
195 |     return this.environment
196 |       ? this.availableEnvironments.get(this.environment)
197 |       : undefined;
198 |   }
199 | 
200 |   async loadAllRequests() {
201 |     try {
202 |       log(`Loading request files from ${this.basePath}`);
203 |       const files = await fs.readdir(this.basePath);
204 |       log(`Found ${files.length} files in directory:`, files);
205 | 
206 |       const requestFiles = files.filter(
207 |         (file) =>
208 |           file.endsWith(".bru") &&
209 |           file !== path.basename(this.collectionPath) &&
210 |           !file.includes("env")
211 |       );
212 | 
213 |       log(`Filtered request files: ${requestFiles.length}`, requestFiles);
214 | 
215 |       for (const file of requestFiles) {
216 |         const requestPath = path.join(this.basePath, file);
217 |         try {
218 |           log(`Loading request from ${requestPath}`);
219 |           const content = await fs.readFile(requestPath, "utf-8");
220 |           const parsed = bruToJson(content);
221 |           const requestName = path.basename(file, ".bru");
222 |           this.parsedRequests.set(requestName, parsed);
223 |           log(`Request loaded: ${requestName}`);
224 |         } catch (error: unknown) {
225 |           const errorMessage =
226 |             error instanceof Error ? error.message : String(error);
227 |           log(`Error parsing request file ${file}: ${errorMessage}`);
228 |         }
229 |       }
230 |       log(`Loaded ${this.parsedRequests.size} requests`);
231 |     } catch (error: unknown) {
232 |       const errorMessage =
233 |         error instanceof Error ? error.message : String(error);
234 |       log(`Error loading request files: ${errorMessage}`);
235 |     }
236 |   }
237 | 
238 |   getAvailableRequests(): string[] {
239 |     return Array.from(this.parsedRequests.keys());
240 |   }
241 | 
242 |   getRawRequest(requestName: string): any | undefined {
243 |     return this.parsedRequests.get(requestName);
244 |   }
245 | 
246 |   async parseCollection(): Promise<any> {
247 |     try {
248 |       const content = await fs.readFile(this.collectionPath, "utf-8");
249 |       return collectionBruToJson(content);
250 |     } catch (error: unknown) {
251 |       const errorMessage =
252 |         error instanceof Error ? error.message : String(error);
253 |       log(`Error parsing collection file: ${errorMessage}`);
254 |       throw error;
255 |     }
256 |   }
257 | 
258 |   getCollection(): any {
259 |     return this.parsedCollection;
260 |   }
261 | 
262 |   async parseRequest(requestInput: string): Promise<ParsedRequest> {
263 |     let rawRequest;
264 |     let requestName;
265 |     let filePath = requestInput;
266 | 
267 |     // If the input is a name and not a path, get the request from loaded requests
268 |     if (!requestInput.includes(path.sep) && !requestInput.endsWith(".bru")) {
269 |       requestName = requestInput;
270 |       rawRequest = this.getRawRequest(requestName);
271 |       if (!rawRequest) {
272 |         throw new Error(`Request not found: ${requestName}`);
273 |       }
274 |     } else {
275 |       // Input is a file path
276 |       requestName = path.basename(requestInput, ".bru");
277 |       try {
278 |         const content = await fs.readFile(filePath, "utf-8");
279 |         rawRequest = bruToJson(content);
280 |       } catch (error: unknown) {
281 |         const errorMessage =
282 |           error instanceof Error ? error.message : String(error);
283 |         throw new Error(
284 |           `Error parsing request file ${filePath}: ${errorMessage}`
285 |         );
286 |       }
287 |     }
288 | 
289 |     // Extract HTTP method and URL
290 |     let method = "GET";
291 |     let url = "";
292 | 
293 |     if (rawRequest.http && rawRequest.http.method) {
294 |       method = rawRequest.http.method.toUpperCase();
295 |     }
296 | 
297 |     if (rawRequest.http && rawRequest.http.url) {
298 |       // Store the original URL without processing variables
299 |       url = rawRequest.http.url;
300 |     }
301 | 
302 |     // Parse headers
303 |     const headers: Record<string, string> = {};
304 | 
305 |     // Handle auth inheritance
306 |     if (
307 |       rawRequest.http &&
308 |       rawRequest.http.auth === "inherit" &&
309 |       this.parsedCollection
310 |     ) {
311 |       const collectionAuth = this.parsedCollection.auth;
312 |       if (collectionAuth && collectionAuth.mode === "apikey") {
313 |         const apiKeyAuth = collectionAuth.apikey;
314 |         if (
315 |           apiKeyAuth &&
316 |           (!apiKeyAuth.addTo || apiKeyAuth.addTo === "header")
317 |         ) {
318 |           headers[apiKeyAuth.key] = this.processTemplateVariables(
319 |             apiKeyAuth.value || ""
320 |           );
321 |         }
322 |       }
323 |     }
324 | 
325 |     // Parse request-specific headers from headers section
326 |     if (rawRequest.headers) {
327 |       for (const header of rawRequest.headers) {
328 |         if (header.enabled !== false && header.name) {
329 |           headers[header.name] = this.processTemplateVariables(
330 |             header.value || ""
331 |           );
332 |         }
333 |       }
334 |     }
335 | 
336 |     // Parse request-specific headers from http.headers (for backward compatibility)
337 |     if (rawRequest.http && rawRequest.http.headers) {
338 |       for (const header of rawRequest.http.headers) {
339 |         if (header.enabled !== false && header.name) {
340 |           headers[header.name] = this.processTemplateVariables(
341 |             header.value || ""
342 |           );
343 |         }
344 |       }
345 |     }
346 | 
347 |     // Parse query parameters
348 |     const queryParams: Record<string, string> = {};
349 | 
350 |     // Parse from params:query section (new format)
351 |     if (rawRequest.params) {
352 |       // Check if params is an array (from paramsquery handler)
353 |       if (Array.isArray(rawRequest.params)) {
354 |         // Find query parameters in params array
355 |         const queryParamsArray = rawRequest.params.filter(
356 |           (param: any) => param.type === "query"
357 |         );
358 |         for (const param of queryParamsArray) {
359 |           if (param.enabled !== false && param.name) {
360 |             queryParams[param.name] = this.processTemplateVariables(
361 |               param.value || ""
362 |             );
363 |           }
364 |         }
365 |       } else if (rawRequest.params.query) {
366 |         // Handle legacy structure
367 |         if (Array.isArray(rawRequest.params.query)) {
368 |           for (const param of rawRequest.params.query) {
369 |             if (param.enabled !== false && param.name) {
370 |               queryParams[param.name] = this.processTemplateVariables(
371 |                 param.value || ""
372 |               );
373 |             }
374 |           }
375 |         } else if (typeof rawRequest.params.query === "object") {
376 |           Object.entries(rawRequest.params.query).forEach(([name, value]) => {
377 |             queryParams[name] = this.processTemplateVariables(String(value));
378 |           });
379 |         }
380 |       }
381 |     }
382 | 
383 |     // Parse from http.query section (backward compatibility)
384 |     if (rawRequest.http && rawRequest.http.query) {
385 |       for (const param of rawRequest.http.query) {
386 |         if (param.enabled !== false && param.name) {
387 |           queryParams[param.name] = this.processTemplateVariables(
388 |             param.value || ""
389 |           );
390 |         }
391 |       }
392 |     }
393 | 
394 |     // Handle query parameter auth
395 |     if (
396 |       rawRequest.http &&
397 |       rawRequest.http.auth === "inherit" &&
398 |       this.parsedCollection
399 |     ) {
400 |       const collectionAuth = this.parsedCollection.auth;
401 |       if (collectionAuth && collectionAuth.mode === "apikey") {
402 |         const apiKeyAuth = collectionAuth.apikey;
403 |         if (apiKeyAuth && apiKeyAuth.addTo === "queryParams") {
404 |           queryParams[apiKeyAuth.key] = this.processTemplateVariables(
405 |             apiKeyAuth.value || ""
406 |           );
407 |           log(
408 |             `Added auth query param: ${apiKeyAuth.key}=${
409 |               queryParams[apiKeyAuth.key]
410 |             }`
411 |           );
412 |         }
413 |       }
414 |     }
415 | 
416 |     // Parse body content
417 |     let body;
418 |     if (rawRequest.http && rawRequest.http.body) {
419 |       const bodyContent = rawRequest.http.body;
420 |       const bodyMode = bodyContent.mode || "json";
421 | 
422 |       // Process body content based on mode
423 |       if (bodyMode === "json" && bodyContent.json) {
424 |         try {
425 |           // If it's a string, try to parse it as JSON
426 |           let processedContent = this.processTemplateVariables(
427 |             bodyContent.json
428 |           );
429 |           let jsonContent;
430 | 
431 |           try {
432 |             jsonContent = JSON.parse(processedContent);
433 |           } catch (e) {
434 |             // If not valid JSON, use as is
435 |             jsonContent = processedContent;
436 |           }
437 | 
438 |           body = {
439 |             type: "json",
440 |             content: jsonContent,
441 |           };
442 |         } catch (error: unknown) {
443 |           const errorMessage =
444 |             error instanceof Error ? error.message : String(error);
445 |           log(`Error processing JSON body: ${errorMessage}`);
446 |           body = {
447 |             type: "json",
448 |             content: bodyContent.json,
449 |           };
450 |         }
451 |       } else if (bodyMode === "text" && bodyContent.text) {
452 |         body = {
453 |           type: "text",
454 |           content: this.processTemplateVariables(bodyContent.text),
455 |         };
456 |       } else if (bodyMode === "form-urlencoded" && bodyContent.formUrlEncoded) {
457 |         const formData: Record<string, string> = {};
458 |         for (const param of bodyContent.formUrlEncoded) {
459 |           if (param.enabled !== false && param.name) {
460 |             formData[param.name] = this.processTemplateVariables(
461 |               param.value || ""
462 |             );
463 |           }
464 |         }
465 |         body = {
466 |           type: "form-urlencoded",
467 |           content: formData,
468 |         };
469 |       } else {
470 |         // For other body types, store as is
471 |         body = {
472 |           type: bodyMode,
473 |           content: bodyContent[bodyMode],
474 |         };
475 |       }
476 |     }
477 | 
478 |     return {
479 |       name: requestName,
480 |       method,
481 |       url,
482 |       rawRequest,
483 |       headers,
484 |       queryParams,
485 |       body,
486 |       filePath,
487 |     };
488 |   }
489 | 
490 |   processTemplateVariables(input: string): string {
491 |     if (!input || typeof input !== "string") {
492 |       return input;
493 |     }
494 | 
495 |     return input.replace(
496 |       TEMPLATE_VAR_REGEX,
497 |       (match: string, varName: string) => {
498 |         const trimmedVarName = varName.trim();
499 |         return this.envVars[trimmedVarName] !== undefined
500 |           ? this.envVars[trimmedVarName]
501 |           : match;
502 |       }
503 |     );
504 |   }
505 | 
506 |   extractTemplateVariables(input: string): string[] {
507 |     if (!input || typeof input !== "string") {
508 |       return [];
509 |     }
510 | 
511 |     const variables: string[] = [];
512 |     let match;
513 |     while ((match = TEMPLATE_VAR_REGEX.exec(input)) !== null) {
514 |       variables.push(match[1].trim());
515 |     }
516 |     return variables;
517 |   }
518 | 
519 |   async executeRequest(
520 |     parsedRequest: ParsedRequest,
521 |     params: {
522 |       variables?: Record<string, any>;
523 |       query?: Record<string, string>;
524 |       body?: any;
525 |     } = {}
526 |   ): Promise<BrunoResponse> {
527 |     // Create a temporary copy of environment variables
528 |     const originalEnvVars = { ...this.envVars };
529 |     console.log("originalEnvVars", originalEnvVars);
530 | 
531 |     try {
532 |       const { method, body, queryParams, rawRequest } = parsedRequest;
533 |       const { variables, query, ...requestParams } = params;
534 | 
535 |       // Apply any custom variables if provided
536 |       if (variables && typeof variables === "object") {
537 |         debugReq(`Applying temporary variables: ${JSON.stringify(variables)}`);
538 |         // Temporarily override environment variables
539 |         Object.entries(variables).forEach(([key, value]) => {
540 |           this.envVars[key] = String(value);
541 | 
542 |           // If a variable matches a query parameter name, update the query parameter as well
543 |           if (Object.prototype.hasOwnProperty.call(queryParams, key)) {
544 |             queryParams[key] = String(value);
545 |           }
546 |         });
547 |       }
548 | 
549 |       // Get the original URL from rawRequest instead of using the pre-processed URL
550 |       const originalUrl = rawRequest?.http?.url || parsedRequest.url;
551 | 
552 |       // Process template variables in the URL with current environment variables
553 |       let finalUrl = this.processTemplateVariables(originalUrl);
554 |       debugReq(`Final URL: ${finalUrl}`);
555 | 
556 |       // Add query parameters that are not already in the URL
557 |       const urlObj = new URL(finalUrl);
558 | 
559 |       // Apply authentication using our new auth module
560 |       const authResult = applyAuthToParsedRequest(
561 |         rawRequest,
562 |         this.parsedCollection,
563 |         this.envVars
564 |       );
565 | 
566 |       // Merge any headers from auth with existing headers from parsedRequest
567 |       const headers = {
568 |         ...parsedRequest.headers,
569 |         ...authResult.headers,
570 |       };
571 | 
572 |       // Apply parameters to query parameters
573 |       if (queryParams) {
574 |         Object.entries(requestParams).forEach(([key, value]) => {
575 |           if (Object.prototype.hasOwnProperty.call(queryParams, key)) {
576 |             queryParams[key] = String(value);
577 |           }
578 |         });
579 |       }
580 | 
581 |       // Add dedicated query parameters if provided
582 |       if (query && typeof query === "object") {
583 |         debugReq(
584 |           `Applying dedicated query parameters: ${JSON.stringify(query)}`
585 |         );
586 |         Object.entries(query).forEach(([key, value]) => {
587 |           queryParams[key] = String(value);
588 |         });
589 |       }
590 | 
591 |       // Add all query parameters to URL, including those from auth
592 |       // First add existing query params from the request
593 |       Object.entries(queryParams).forEach(([key, value]) => {
594 |         urlObj.searchParams.set(key, value);
595 |       });
596 | 
597 |       // Then add auth query params if any
598 |       if (authResult.queryParams) {
599 |         Object.entries(authResult.queryParams).forEach(([key, value]) => {
600 |           urlObj.searchParams.set(key, value);
601 |         });
602 |       }
603 | 
604 |       finalUrl = urlObj.toString();
605 | 
606 |       // Process body content with parameters if it's JSON
607 |       let requestData = params.body;
608 | 
609 |       debugReq(`Executing ${method} request to ${finalUrl}`);
610 |       debugReq(`Headers: ${JSON.stringify(headers)}`);
611 |       if (requestData) {
612 |         debugReq(
613 |           `Body: ${
614 |             typeof requestData === "object"
615 |               ? JSON.stringify(requestData)
616 |               : requestData
617 |           }`
618 |         );
619 |       }
620 | 
621 |       // Send the request
622 |       const response = await axios({
623 |         method,
624 |         url: finalUrl,
625 |         headers,
626 |         data: requestData,
627 |         validateStatus: () => true, // Don't throw on any status code
628 |       });
629 | 
630 |       // Log response status
631 |       debugReq(`Response status: ${response.status}`);
632 | 
633 |       // Check if the response is JSON by examining the content-type header
634 |       const contentType = response.headers["content-type"] || "";
635 |       const isJson = contentType.includes("application/json");
636 | 
637 |       if (!isJson) {
638 |         debugReq(
639 |           `Warning: Response is not JSON (content-type: ${contentType})`
640 |         );
641 |       }
642 |       console.log("response.data", response.data);
643 | 
644 |       // Return structured response
645 |       return {
646 |         status: response.status,
647 |         headers: response.headers,
648 |         data: response.data,
649 |         isJson,
650 |       };
651 |     } catch (error: unknown) {
652 |       const errorMessage =
653 |         error instanceof Error ? error.message : String(error);
654 |       debugReq(`Error executing request: ${errorMessage}`);
655 |       return {
656 |         status: 0,
657 |         headers: {},
658 |         data: errorMessage,
659 |         error: true,
660 |       };
661 |     } finally {
662 |       // Restore original environment variables
663 |       this.envVars = originalEnvVars;
664 |     }
665 |   }
666 | 
667 |   hasTemplateVariable(url: string, varName: string): boolean {
668 |     const templateVars = this.extractTemplateVariables(url);
669 |     return templateVars.includes(varName);
670 |   }
671 | }
672 | 
```

--------------------------------------------------------------------------------
/src/bruno-lang/bruToJson.js:
--------------------------------------------------------------------------------

```javascript
  1 | import ohm from "ohm-js";
  2 | import _ from "lodash";
  3 | import { outdentString } from "../bruno-utils.js";
  4 | 
  5 | /**
  6 |  * A Bru file is made up of blocks.
  7 |  * There are two types of blocks
  8 |  *
  9 |  * 1. Dictionary Blocks - These are blocks that have key value pairs
 10 |  * ex:
 11 |  *  headers {
 12 |  *   content-type: application/json
 13 |  *  }
 14 |  *
 15 |  * 2. Text Blocks - These are blocks that have text
 16 |  * ex:
 17 |  * body:json {
 18 |  *  {
 19 |  *   "username": "John Nash",
 20 |  *   "password": "governingdynamics
 21 |  *  }
 22 |  *
 23 |  */
 24 | const grammar = ohm.grammar(`Bru {
 25 |   BruFile = (meta | http | query | params | headers | auths | bodies | varsandassert | script | tests | docs)*
 26 |   auths = authawsv4 | authbasic | authbearer | authdigest | authNTLM | authOAuth2 | authwsse | authapikey
 27 |   bodies = bodyjson | bodytext | bodyxml | bodysparql | bodygraphql | bodygraphqlvars | bodyforms | body
 28 |   bodyforms = bodyformurlencoded | bodymultipart | bodyfile
 29 |   params = paramspath | paramsquery
 30 | 
 31 |   nl = "\\r"? "\\n"
 32 |   st = " " | "\\t"
 33 |   stnl = st | nl
 34 |   tagend = nl "}"
 35 |   optionalnl = ~tagend nl
 36 |   keychar = ~(tagend | st | nl | ":") any
 37 |   valuechar = ~(nl | tagend) any
 38 | 
 39 |    // Multiline text block surrounded by '''
 40 |   multilinetextblockdelimiter = "'''"
 41 |   multilinetextblock = multilinetextblockdelimiter (~multilinetextblockdelimiter any)* multilinetextblockdelimiter
 42 | 
 43 |   // Dictionary Blocks
 44 |   dictionary = st* "{" pairlist? tagend
 45 |   pairlist = optionalnl* pair (~tagend stnl* pair)* (~tagend space)*
 46 |   pair = st* key st* ":" st* value st*
 47 |   key = keychar*
 48 |   value = multilinetextblock | valuechar*
 49 | 
 50 |   // Dictionary for Assert Block
 51 |   assertdictionary = st* "{" assertpairlist? tagend
 52 |   assertpairlist = optionalnl* assertpair (~tagend stnl* assertpair)* (~tagend space)*
 53 |   assertpair = st* assertkey st* ":" st* value st*
 54 |   assertkey = ~tagend assertkeychar*
 55 |   assertkeychar = ~(tagend | nl | ":") any
 56 | 
 57 |   // Text Blocks
 58 |   textblock = textline (~tagend nl textline)*
 59 |   textline = textchar*
 60 |   textchar = ~nl any
 61 | 
 62 |   meta = "meta" dictionary
 63 | 
 64 |   http = get | post | put | delete | patch | options | head | connect | trace
 65 |   get = "get" dictionary
 66 |   post = "post" dictionary
 67 |   put = "put" dictionary
 68 |   delete = "delete" dictionary
 69 |   patch = "patch" dictionary
 70 |   options = "options" dictionary
 71 |   head = "head" dictionary
 72 |   connect = "connect" dictionary
 73 |   trace = "trace" dictionary
 74 | 
 75 |   headers = "headers" dictionary
 76 | 
 77 |   query = "query" dictionary
 78 |   paramspath = "params:path" dictionary
 79 |   paramsquery = "params:query" dictionary
 80 | 
 81 |   varsandassert = varsreq | varsres | assert
 82 |   varsreq = "vars:pre-request" dictionary
 83 |   varsres = "vars:post-response" dictionary
 84 |   assert = "assert" assertdictionary
 85 | 
 86 |   authawsv4 = "auth:awsv4" dictionary
 87 |   authbasic = "auth:basic" dictionary
 88 |   authbearer = "auth:bearer" dictionary
 89 |   authdigest = "auth:digest" dictionary
 90 |   authNTLM = "auth:ntlm" dictionary
 91 |   authOAuth2 = "auth:oauth2" dictionary
 92 |   authwsse = "auth:wsse" dictionary
 93 |   authapikey = "auth:apikey" dictionary
 94 | 
 95 |   body = "body" st* "{" nl* textblock tagend
 96 |   bodyjson = "body:json" st* "{" nl* textblock tagend
 97 |   bodytext = "body:text" st* "{" nl* textblock tagend
 98 |   bodyxml = "body:xml" st* "{" nl* textblock tagend
 99 |   bodysparql = "body:sparql" st* "{" nl* textblock tagend
100 |   bodygraphql = "body:graphql" st* "{" nl* textblock tagend
101 |   bodygraphqlvars = "body:graphql:vars" st* "{" nl* textblock tagend
102 | 
103 |   bodyformurlencoded = "body:form-urlencoded" dictionary
104 |   bodymultipart = "body:multipart-form" dictionary
105 |   bodyfile = "body:file" dictionary
106 |   
107 |   script = scriptreq | scriptres
108 |   scriptreq = "script:pre-request" st* "{" nl* textblock tagend
109 |   scriptres = "script:post-response" st* "{" nl* textblock tagend
110 |   tests = "tests" st* "{" nl* textblock tagend
111 |   docs = "docs" st* "{" nl* textblock tagend
112 | }`);
113 | 
114 | const mapPairListToKeyValPairs = (pairList = [], parseEnabled = true) => {
115 |   if (!pairList.length) {
116 |     return [];
117 |   }
118 |   return _.map(pairList[0], (pair) => {
119 |     let name = _.keys(pair)[0];
120 |     let value = pair[name];
121 | 
122 |     if (!parseEnabled) {
123 |       return {
124 |         name,
125 |         value,
126 |       };
127 |     }
128 | 
129 |     let enabled = true;
130 |     if (name && name.length && name.charAt(0) === "~") {
131 |       name = name.slice(1);
132 |       enabled = false;
133 |     }
134 | 
135 |     return {
136 |       name,
137 |       value,
138 |       enabled,
139 |     };
140 |   });
141 | };
142 | 
143 | const mapRequestParams = (pairList = [], type) => {
144 |   if (!pairList.length) {
145 |     return [];
146 |   }
147 |   return _.map(pairList[0], (pair) => {
148 |     let name = _.keys(pair)[0];
149 |     let value = pair[name];
150 |     let enabled = true;
151 |     if (name && name.length && name.charAt(0) === "~") {
152 |       name = name.slice(1);
153 |       enabled = false;
154 |     }
155 | 
156 |     return {
157 |       name,
158 |       value,
159 |       enabled,
160 |       type,
161 |     };
162 |   });
163 | };
164 | 
165 | const multipartExtractContentType = (pair) => {
166 |   if (_.isString(pair.value)) {
167 |     const match = pair.value.match(/^(.*?)\s*@contentType\((.*?)\)\s*$/);
168 |     if (match != null && match.length > 2) {
169 |       pair.value = match[1];
170 |       pair.contentType = match[2];
171 |     } else {
172 |       pair.contentType = "";
173 |     }
174 |   }
175 | };
176 | 
177 | const fileExtractContentType = (pair) => {
178 |   if (_.isString(pair.value)) {
179 |     const match = pair.value.match(/^(.*?)\s*@contentType\((.*?)\)\s*$/);
180 |     if (match && match.length > 2) {
181 |       pair.value = match[1].trim();
182 |       pair.contentType = match[2].trim();
183 |     } else {
184 |       pair.contentType = "";
185 |     }
186 |   }
187 | };
188 | 
189 | const mapPairListToKeyValPairsMultipart = (
190 |   pairList = [],
191 |   parseEnabled = true
192 | ) => {
193 |   const pairs = mapPairListToKeyValPairs(pairList, parseEnabled);
194 | 
195 |   return pairs.map((pair) => {
196 |     pair.type = "text";
197 |     multipartExtractContentType(pair);
198 | 
199 |     if (pair.value.startsWith("@file(") && pair.value.endsWith(")")) {
200 |       let filestr = pair.value.replace(/^@file\(/, "").replace(/\)$/, "");
201 |       pair.type = "file";
202 |       pair.value = filestr.split("|");
203 |     }
204 | 
205 |     return pair;
206 |   });
207 | };
208 | 
209 | const mapPairListToKeyValPairsFile = (pairList = [], parseEnabled = true) => {
210 |   const pairs = mapPairListToKeyValPairs(pairList, parseEnabled);
211 |   return pairs.map((pair) => {
212 |     fileExtractContentType(pair);
213 | 
214 |     if (pair.value.startsWith("@file(") && pair.value.endsWith(")")) {
215 |       let filePath = pair.value.replace(/^@file\(/, "").replace(/\)$/, "");
216 |       pair.filePath = filePath;
217 |       pair.selected = pair.enabled;
218 | 
219 |       // Remove pair.value as it only contains the file path reference
220 |       delete pair.value;
221 |       // Remove pair.name as it is auto-generated (e.g., file1, file2, file3, etc.)
222 |       delete pair.name;
223 |       delete pair.enabled;
224 |     }
225 | 
226 |     return pair;
227 |   });
228 | };
229 | 
230 | const concatArrays = (objValue, srcValue) => {
231 |   if (_.isArray(objValue) && _.isArray(srcValue)) {
232 |     return objValue.concat(srcValue);
233 |   }
234 | };
235 | 
236 | const mapPairListToKeyValPair = (pairList = []) => {
237 |   if (!pairList || !pairList.length) {
238 |     return {};
239 |   }
240 | 
241 |   return _.merge({}, ...pairList[0]);
242 | };
243 | 
244 | const sem = grammar.createSemantics().addAttribute("ast", {
245 |   BruFile(tags) {
246 |     if (!tags || !tags.ast || !tags.ast.length) {
247 |       return {};
248 |     }
249 | 
250 |     return _.reduce(
251 |       tags.ast,
252 |       (result, item) => {
253 |         return _.mergeWith(result, item, concatArrays);
254 |       },
255 |       {}
256 |     );
257 |   },
258 |   dictionary(_1, _2, pairlist, _3) {
259 |     return pairlist.ast;
260 |   },
261 |   pairlist(_1, pair, _2, rest, _3) {
262 |     return [pair.ast, ...rest.ast];
263 |   },
264 |   pair(_1, key, _2, _3, _4, value, _5) {
265 |     let res = {};
266 |     res[key.ast] = value.ast ? value.ast.trim() : "";
267 |     return res;
268 |   },
269 |   key(chars) {
270 |     return chars.sourceString ? chars.sourceString.trim() : "";
271 |   },
272 |   value(chars) {
273 |     try {
274 |       let isMultiline =
275 |         chars.sourceString?.startsWith(`'''`) &&
276 |         chars.sourceString?.endsWith(`'''`);
277 |       if (isMultiline) {
278 |         const multilineString = chars.sourceString?.replace(/^'''|'''$/g, "");
279 |         return multilineString
280 |           .split("\n")
281 |           .map((line) => line.slice(4))
282 |           .join("\n");
283 |       }
284 |       return chars.sourceString ? chars.sourceString.trim() : "";
285 |     } catch (err) {
286 |       console.error(err);
287 |     }
288 |     return chars.sourceString ? chars.sourceString.trim() : "";
289 |   },
290 |   assertdictionary(_1, _2, pairlist, _3) {
291 |     return pairlist.ast;
292 |   },
293 |   assertpairlist(_1, pair, _2, rest, _3) {
294 |     return [pair.ast, ...rest.ast];
295 |   },
296 |   assertpair(_1, key, _2, _3, _4, value, _5) {
297 |     let res = {};
298 |     res[key.ast] = value.ast ? value.ast.trim() : "";
299 |     return res;
300 |   },
301 |   assertkey(chars) {
302 |     return chars.sourceString ? chars.sourceString.trim() : "";
303 |   },
304 |   textblock(line, _1, rest) {
305 |     return [line.ast, ...rest.ast].join("\n");
306 |   },
307 |   textline(chars) {
308 |     return chars.sourceString;
309 |   },
310 |   textchar(char) {
311 |     return char.sourceString;
312 |   },
313 |   nl(_1, _2) {
314 |     return "";
315 |   },
316 |   st(_) {
317 |     return "";
318 |   },
319 |   tagend(_1, _2) {
320 |     return "";
321 |   },
322 |   _iter(...elements) {
323 |     return elements.map((e) => e.ast);
324 |   },
325 |   meta(_1, dictionary) {
326 |     let meta = mapPairListToKeyValPair(dictionary.ast);
327 | 
328 |     if (!meta.seq) {
329 |       meta.seq = 1;
330 |     }
331 | 
332 |     if (!meta.type) {
333 |       meta.type = "http";
334 |     }
335 | 
336 |     return {
337 |       meta,
338 |     };
339 |   },
340 |   get(_1, dictionary) {
341 |     return {
342 |       http: {
343 |         method: "get",
344 |         ...mapPairListToKeyValPair(dictionary.ast),
345 |       },
346 |     };
347 |   },
348 |   post(_1, dictionary) {
349 |     return {
350 |       http: {
351 |         method: "post",
352 |         ...mapPairListToKeyValPair(dictionary.ast),
353 |       },
354 |     };
355 |   },
356 |   put(_1, dictionary) {
357 |     return {
358 |       http: {
359 |         method: "put",
360 |         ...mapPairListToKeyValPair(dictionary.ast),
361 |       },
362 |     };
363 |   },
364 |   delete(_1, dictionary) {
365 |     return {
366 |       http: {
367 |         method: "delete",
368 |         ...mapPairListToKeyValPair(dictionary.ast),
369 |       },
370 |     };
371 |   },
372 |   patch(_1, dictionary) {
373 |     return {
374 |       http: {
375 |         method: "patch",
376 |         ...mapPairListToKeyValPair(dictionary.ast),
377 |       },
378 |     };
379 |   },
380 |   options(_1, dictionary) {
381 |     return {
382 |       http: {
383 |         method: "options",
384 |         ...mapPairListToKeyValPair(dictionary.ast),
385 |       },
386 |     };
387 |   },
388 |   head(_1, dictionary) {
389 |     return {
390 |       http: {
391 |         method: "head",
392 |         ...mapPairListToKeyValPair(dictionary.ast),
393 |       },
394 |     };
395 |   },
396 |   connect(_1, dictionary) {
397 |     return {
398 |       http: {
399 |         method: "connect",
400 |         ...mapPairListToKeyValPair(dictionary.ast),
401 |       },
402 |     };
403 |   },
404 |   query(_1, dictionary) {
405 |     return {
406 |       params: mapRequestParams(dictionary.ast, "query"),
407 |     };
408 |   },
409 |   paramspath(_1, dictionary) {
410 |     return {
411 |       params: mapRequestParams(dictionary.ast, "path"),
412 |     };
413 |   },
414 |   paramsquery(_1, dictionary) {
415 |     return {
416 |       params: mapRequestParams(dictionary.ast, "query"),
417 |     };
418 |   },
419 |   headers(_1, dictionary) {
420 |     return {
421 |       headers: mapPairListToKeyValPairs(dictionary.ast),
422 |     };
423 |   },
424 |   authawsv4(_1, dictionary) {
425 |     const auth = mapPairListToKeyValPairs(dictionary.ast, false);
426 |     const accessKeyIdKey = _.find(auth, { name: "accessKeyId" });
427 |     const secretAccessKeyKey = _.find(auth, { name: "secretAccessKey" });
428 |     const sessionTokenKey = _.find(auth, { name: "sessionToken" });
429 |     const serviceKey = _.find(auth, { name: "service" });
430 |     const regionKey = _.find(auth, { name: "region" });
431 |     const profileNameKey = _.find(auth, { name: "profileName" });
432 |     const accessKeyId = accessKeyIdKey ? accessKeyIdKey.value : "";
433 |     const secretAccessKey = secretAccessKeyKey ? secretAccessKeyKey.value : "";
434 |     const sessionToken = sessionTokenKey ? sessionTokenKey.value : "";
435 |     const service = serviceKey ? serviceKey.value : "";
436 |     const region = regionKey ? regionKey.value : "";
437 |     const profileName = profileNameKey ? profileNameKey.value : "";
438 |     return {
439 |       auth: {
440 |         awsv4: {
441 |           accessKeyId,
442 |           secretAccessKey,
443 |           sessionToken,
444 |           service,
445 |           region,
446 |           profileName,
447 |         },
448 |       },
449 |     };
450 |   },
451 |   authbasic(_1, dictionary) {
452 |     const auth = mapPairListToKeyValPairs(dictionary.ast, false);
453 |     const usernameKey = _.find(auth, { name: "username" });
454 |     const passwordKey = _.find(auth, { name: "password" });
455 |     const username = usernameKey ? usernameKey.value : "";
456 |     const password = passwordKey ? passwordKey.value : "";
457 |     return {
458 |       auth: {
459 |         basic: {
460 |           username,
461 |           password,
462 |         },
463 |       },
464 |     };
465 |   },
466 |   authbearer(_1, dictionary) {
467 |     const auth = mapPairListToKeyValPairs(dictionary.ast, false);
468 |     const tokenKey = _.find(auth, { name: "token" });
469 |     const token = tokenKey ? tokenKey.value : "";
470 |     return {
471 |       auth: {
472 |         bearer: {
473 |           token,
474 |         },
475 |       },
476 |     };
477 |   },
478 |   authdigest(_1, dictionary) {
479 |     const auth = mapPairListToKeyValPairs(dictionary.ast, false);
480 |     const usernameKey = _.find(auth, { name: "username" });
481 |     const passwordKey = _.find(auth, { name: "password" });
482 |     const username = usernameKey ? usernameKey.value : "";
483 |     const password = passwordKey ? passwordKey.value : "";
484 |     return {
485 |       auth: {
486 |         digest: {
487 |           username,
488 |           password,
489 |         },
490 |       },
491 |     };
492 |   },
493 |   authNTLM(_1, dictionary) {
494 |     const auth = mapPairListToKeyValPairs(dictionary.ast, false);
495 |     const usernameKey = _.find(auth, { name: "username" });
496 |     const passwordKey = _.find(auth, { name: "password" });
497 |     const domainKey = _.find(auth, { name: "domain" });
498 | 
499 |     const username = usernameKey ? usernameKey.value : "";
500 |     const password = passwordKey ? passwordKey.value : "";
501 |     const domain = passwordKey ? domainKey.value : "";
502 | 
503 |     return {
504 |       auth: {
505 |         ntlm: {
506 |           username,
507 |           password,
508 |           domain,
509 |         },
510 |       },
511 |     };
512 |   },
513 |   authOAuth2(_1, dictionary) {
514 |     const auth = mapPairListToKeyValPairs(dictionary.ast, false);
515 |     const grantTypeKey = _.find(auth, { name: "grant_type" });
516 |     const usernameKey = _.find(auth, { name: "username" });
517 |     const passwordKey = _.find(auth, { name: "password" });
518 |     const callbackUrlKey = _.find(auth, { name: "callback_url" });
519 |     const authorizationUrlKey = _.find(auth, { name: "authorization_url" });
520 |     const accessTokenUrlKey = _.find(auth, { name: "access_token_url" });
521 |     const refreshTokenUrlKey = _.find(auth, { name: "refresh_token_url" });
522 |     const clientIdKey = _.find(auth, { name: "client_id" });
523 |     const clientSecretKey = _.find(auth, { name: "client_secret" });
524 |     const scopeKey = _.find(auth, { name: "scope" });
525 |     const stateKey = _.find(auth, { name: "state" });
526 |     const pkceKey = _.find(auth, { name: "pkce" });
527 |     const credentialsPlacementKey = _.find(auth, {
528 |       name: "credentials_placement",
529 |     });
530 |     const credentialsIdKey = _.find(auth, { name: "credentials_id" });
531 |     const tokenPlacementKey = _.find(auth, { name: "token_placement" });
532 |     const tokenHeaderPrefixKey = _.find(auth, { name: "token_header_prefix" });
533 |     const tokenQueryKeyKey = _.find(auth, { name: "token_query_key" });
534 |     const autoFetchTokenKey = _.find(auth, { name: "auto_fetch_token" });
535 |     const autoRefreshTokenKey = _.find(auth, { name: "auto_refresh_token" });
536 |     return {
537 |       auth: {
538 |         oauth2:
539 |           grantTypeKey?.value && grantTypeKey?.value == "password"
540 |             ? {
541 |                 grantType: grantTypeKey ? grantTypeKey.value : "",
542 |                 accessTokenUrl: accessTokenUrlKey
543 |                   ? accessTokenUrlKey.value
544 |                   : "",
545 |                 refreshTokenUrl: refreshTokenUrlKey
546 |                   ? refreshTokenUrlKey.value
547 |                   : "",
548 |                 username: usernameKey ? usernameKey.value : "",
549 |                 password: passwordKey ? passwordKey.value : "",
550 |                 clientId: clientIdKey ? clientIdKey.value : "",
551 |                 clientSecret: clientSecretKey ? clientSecretKey.value : "",
552 |                 scope: scopeKey ? scopeKey.value : "",
553 |                 credentialsPlacement: credentialsPlacementKey?.value
554 |                   ? credentialsPlacementKey.value
555 |                   : "body",
556 |                 credentialsId: credentialsIdKey?.value
557 |                   ? credentialsIdKey.value
558 |                   : "credentials",
559 |                 tokenPlacement: tokenPlacementKey?.value
560 |                   ? tokenPlacementKey.value
561 |                   : "header",
562 |                 tokenHeaderPrefix: tokenHeaderPrefixKey?.value
563 |                   ? tokenHeaderPrefixKey.value
564 |                   : "Bearer",
565 |                 tokenQueryKey: tokenQueryKeyKey?.value
566 |                   ? tokenQueryKeyKey.value
567 |                   : "access_token",
568 |                 autoFetchToken: autoFetchTokenKey
569 |                   ? JSON.parse(autoFetchTokenKey?.value)
570 |                   : true,
571 |                 autoRefreshToken: autoRefreshTokenKey
572 |                   ? JSON.parse(autoRefreshTokenKey?.value)
573 |                   : true,
574 |               }
575 |             : grantTypeKey?.value && grantTypeKey?.value == "authorization_code"
576 |             ? {
577 |                 grantType: grantTypeKey ? grantTypeKey.value : "",
578 |                 callbackUrl: callbackUrlKey ? callbackUrlKey.value : "",
579 |                 authorizationUrl: authorizationUrlKey
580 |                   ? authorizationUrlKey.value
581 |                   : "",
582 |                 accessTokenUrl: accessTokenUrlKey
583 |                   ? accessTokenUrlKey.value
584 |                   : "",
585 |                 refreshTokenUrl: refreshTokenUrlKey
586 |                   ? refreshTokenUrlKey.value
587 |                   : "",
588 |                 clientId: clientIdKey ? clientIdKey.value : "",
589 |                 clientSecret: clientSecretKey ? clientSecretKey.value : "",
590 |                 scope: scopeKey ? scopeKey.value : "",
591 |                 state: stateKey ? stateKey.value : "",
592 |                 pkce: pkceKey ? JSON.parse(pkceKey?.value || false) : false,
593 |                 credentialsPlacement: credentialsPlacementKey?.value
594 |                   ? credentialsPlacementKey.value
595 |                   : "body",
596 |                 credentialsId: credentialsIdKey?.value
597 |                   ? credentialsIdKey.value
598 |                   : "credentials",
599 |                 tokenPlacement: tokenPlacementKey?.value
600 |                   ? tokenPlacementKey.value
601 |                   : "header",
602 |                 tokenHeaderPrefix: tokenHeaderPrefixKey?.value
603 |                   ? tokenHeaderPrefixKey.value
604 |                   : "Bearer",
605 |                 tokenQueryKey: tokenQueryKeyKey?.value
606 |                   ? tokenQueryKeyKey.value
607 |                   : "access_token",
608 |                 autoFetchToken: autoFetchTokenKey
609 |                   ? JSON.parse(autoFetchTokenKey?.value)
610 |                   : true,
611 |                 autoRefreshToken: autoRefreshTokenKey
612 |                   ? JSON.parse(autoRefreshTokenKey?.value)
613 |                   : true,
614 |               }
615 |             : grantTypeKey?.value && grantTypeKey?.value == "client_credentials"
616 |             ? {
617 |                 grantType: grantTypeKey ? grantTypeKey.value : "",
618 |                 accessTokenUrl: accessTokenUrlKey
619 |                   ? accessTokenUrlKey.value
620 |                   : "",
621 |                 refreshTokenUrl: refreshTokenUrlKey
622 |                   ? refreshTokenUrlKey.value
623 |                   : "",
624 |                 clientId: clientIdKey ? clientIdKey.value : "",
625 |                 clientSecret: clientSecretKey ? clientSecretKey.value : "",
626 |                 scope: scopeKey ? scopeKey.value : "",
627 |                 credentialsPlacement: credentialsPlacementKey?.value
628 |                   ? credentialsPlacementKey.value
629 |                   : "body",
630 |                 credentialsId: credentialsIdKey?.value
631 |                   ? credentialsIdKey.value
632 |                   : "credentials",
633 |                 tokenPlacement: tokenPlacementKey?.value
634 |                   ? tokenPlacementKey.value
635 |                   : "header",
636 |                 tokenHeaderPrefix: tokenHeaderPrefixKey?.value
637 |                   ? tokenHeaderPrefixKey.value
638 |                   : "Bearer",
639 |                 tokenQueryKey: tokenQueryKeyKey?.value
640 |                   ? tokenQueryKeyKey.value
641 |                   : "access_token",
642 |                 autoFetchToken: autoFetchTokenKey
643 |                   ? JSON.parse(autoFetchTokenKey?.value)
644 |                   : true,
645 |                 autoRefreshToken: autoRefreshTokenKey
646 |                   ? JSON.parse(autoRefreshTokenKey?.value)
647 |                   : true,
648 |               }
649 |             : {},
650 |       },
651 |     };
652 |   },
653 |   authwsse(_1, dictionary) {
654 |     const auth = mapPairListToKeyValPairs(dictionary.ast, false);
655 | 
656 |     const userKey = _.find(auth, { name: "username" });
657 |     const secretKey = _.find(auth, { name: "password" });
658 |     const username = userKey ? userKey.value : "";
659 |     const password = secretKey ? secretKey.value : "";
660 | 
661 |     return {
662 |       auth: {
663 |         wsse: {
664 |           username,
665 |           password,
666 |         },
667 |       },
668 |     };
669 |   },
670 |   authapikey(_1, dictionary) {
671 |     const auth = mapPairListToKeyValPairs(dictionary.ast, false);
672 | 
673 |     const findValueByName = (name) => {
674 |       const item = _.find(auth, { name });
675 |       return item ? item.value : "";
676 |     };
677 | 
678 |     const key = findValueByName("key");
679 |     const value = findValueByName("value");
680 |     const placement = findValueByName("placement");
681 | 
682 |     return {
683 |       auth: {
684 |         apikey: {
685 |           key,
686 |           value,
687 |           placement,
688 |         },
689 |       },
690 |     };
691 |   },
692 |   bodyformurlencoded(_1, dictionary) {
693 |     return {
694 |       body: {
695 |         formUrlEncoded: mapPairListToKeyValPairs(dictionary.ast),
696 |       },
697 |     };
698 |   },
699 |   bodymultipart(_1, dictionary) {
700 |     return {
701 |       body: {
702 |         multipartForm: mapPairListToKeyValPairsMultipart(dictionary.ast),
703 |       },
704 |     };
705 |   },
706 |   bodyfile(_1, dictionary) {
707 |     return {
708 |       body: {
709 |         file: mapPairListToKeyValPairsFile(dictionary.ast),
710 |       },
711 |     };
712 |   },
713 |   body(_1, _2, _3, _4, textblock, _5) {
714 |     return {
715 |       http: {
716 |         body: "json",
717 |       },
718 |       body: {
719 |         json: outdentString(textblock.sourceString),
720 |       },
721 |     };
722 |   },
723 |   bodyjson(_1, _2, _3, _4, textblock, _5) {
724 |     return {
725 |       body: {
726 |         json: outdentString(textblock.sourceString),
727 |       },
728 |     };
729 |   },
730 |   bodytext(_1, _2, _3, _4, textblock, _5) {
731 |     return {
732 |       body: {
733 |         text: outdentString(textblock.sourceString),
734 |       },
735 |     };
736 |   },
737 |   bodyxml(_1, _2, _3, _4, textblock, _5) {
738 |     return {
739 |       body: {
740 |         xml: outdentString(textblock.sourceString),
741 |       },
742 |     };
743 |   },
744 |   bodysparql(_1, _2, _3, _4, textblock, _5) {
745 |     return {
746 |       body: {
747 |         sparql: outdentString(textblock.sourceString),
748 |       },
749 |     };
750 |   },
751 |   bodygraphql(_1, _2, _3, _4, textblock, _5) {
752 |     return {
753 |       body: {
754 |         graphql: {
755 |           query: outdentString(textblock.sourceString),
756 |         },
757 |       },
758 |     };
759 |   },
760 |   bodygraphqlvars(_1, _2, _3, _4, textblock, _5) {
761 |     return {
762 |       body: {
763 |         graphql: {
764 |           variables: outdentString(textblock.sourceString),
765 |         },
766 |       },
767 |     };
768 |   },
769 |   varsreq(_1, dictionary) {
770 |     const vars = mapPairListToKeyValPairs(dictionary.ast);
771 |     _.each(vars, (v) => {
772 |       let name = v.name;
773 |       if (name && name.length && name.charAt(0) === "@") {
774 |         v.name = name.slice(1);
775 |         v.local = true;
776 |       } else {
777 |         v.local = false;
778 |       }
779 |     });
780 | 
781 |     return {
782 |       vars: {
783 |         req: vars,
784 |       },
785 |     };
786 |   },
787 |   varsres(_1, dictionary) {
788 |     const vars = mapPairListToKeyValPairs(dictionary.ast);
789 |     _.each(vars, (v) => {
790 |       let name = v.name;
791 |       if (name && name.length && name.charAt(0) === "@") {
792 |         v.name = name.slice(1);
793 |         v.local = true;
794 |       } else {
795 |         v.local = false;
796 |       }
797 |     });
798 | 
799 |     return {
800 |       vars: {
801 |         res: vars,
802 |       },
803 |     };
804 |   },
805 |   assert(_1, dictionary) {
806 |     return {
807 |       assertions: mapPairListToKeyValPairs(dictionary.ast),
808 |     };
809 |   },
810 |   scriptreq(_1, _2, _3, _4, textblock, _5) {
811 |     return {
812 |       script: {
813 |         req: outdentString(textblock.sourceString),
814 |       },
815 |     };
816 |   },
817 |   scriptres(_1, _2, _3, _4, textblock, _5) {
818 |     return {
819 |       script: {
820 |         res: outdentString(textblock.sourceString),
821 |       },
822 |     };
823 |   },
824 |   tests(_1, _2, _3, _4, textblock, _5) {
825 |     return {
826 |       tests: outdentString(textblock.sourceString),
827 |     };
828 |   },
829 |   docs(_1, _2, _3, _4, textblock, _5) {
830 |     return {
831 |       docs: outdentString(textblock.sourceString),
832 |     };
833 |   },
834 | });
835 | 
836 | const parser = (input) => {
837 |   const match = grammar.match(input);
838 | 
839 |   if (match.succeeded()) {
840 |     return sem(match).ast;
841 |   } else {
842 |     throw new Error(match.message);
843 |   }
844 | };
845 | 
846 | export default parser;
847 | 
```
Page 2/2FirstPrevNextLast