From d91600fe269051f005bc0efed5ef5eb798194322 Mon Sep 17 00:00:00 2001 From: Dung Huynh Duc Date: Wed, 23 Oct 2024 21:37:59 +0800 Subject: [PATCH] feat: add support for capturing and managing global variables --- README.md | 10 +++++---- package.json | 21 ++++++++++++++++-- pnpm-lock.yaml | 16 +++++++------- src/hurl-variables-provider.ts | 16 +++++++++++++- src/hurl-variables-tree-provider.ts | 22 +++++++++++++++++++ src/index.ts | 33 ++++++++++++++++++++++++++++- src/manage-variables.ts | 13 ++++++++++++ 7 files changed, 115 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 121b776..3829592 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ | `vscode-hurl-runner.rerunLastCommand` | Hurl Runner: Rerun Last Command | | `vscode-hurl-runner.runHurlFromBegin` | Hurl Runner: Run from Begin to Current | | `vscode-hurl-runner.viewLastResponse` | Hurl Runner: View Last Response | +| `vscode-hurl-runner.removeGlobalVariable` | Remove Global Variable | @@ -56,10 +57,11 @@ -| Key | Description | Type | Default | -| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ----------- | -| `vscode-hurl-runner.hurlPath` | Path to the Hurl executable | `string` | `"hurl"` | -| `vscode-hurl-runner.verboseMode` | Set the verbosity level for Hurl execution. 'verbose' provides basic information about requests and responses. 'very-verbose' includes detailed information, including timing data. | `string` | `"verbose"` | +| Key | Description | Type | Default | +| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------- | +| `vscode-hurl-runner.hurlPath` | Path to the Hurl executable | `string` | `"hurl"` | +| `vscode-hurl-runner.verboseMode` | Set the verbosity level for Hurl execution. 'verbose' provides basic information about requests and responses. 'very-verbose' includes detailed information, including timing data. | `string` | `"verbose"` | +| `vscode-hurl-runner.captureToGlobalVariable` | When enabled, captured values will be set as global variables. | `boolean` | `false` | diff --git a/package.json b/package.json index 82306a8..8bdbc07 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,10 @@ { "command": "vscode-hurl-runner.viewLastResponse", "title": "Hurl Runner: View Last Response" + }, + { + "command": "vscode-hurl-runner.removeGlobalVariable", + "title": "Remove Global Variable" } ], "viewsContainers": { @@ -108,6 +112,11 @@ "enum": ["verbose", "very-verbose"], "default": "verbose", "description": "Set the verbosity level for Hurl execution. 'verbose' provides basic information about requests and responses. 'very-verbose' includes detailed information, including timing data." + }, + "vscode-hurl-runner.captureToGlobalVariable": { + "type": "boolean", + "default": false, + "description": "When enabled, captured values will be set as global variables." } } }, @@ -181,14 +190,22 @@ "scopeName": "source.hurl", "path": "./syntaxes/hurl.tmLanguage.json" } - ] + ], + "menus": { + "view/item/context": [ + { + "command": "vscode-hurl-runner.removeGlobalVariable", + "when": "view == hurlVariables && viewItem == globalVariable" + } + ] + } }, "activationEvents": ["onLanguage:hurl"], "devDependencies": { "@antfu/ni": "0.23.0", "@biomejs/biome": "1.9.4", "@types/node": "22.7.9", - "@types/vscode": "1.94.0", + "@types/vscode": "1.93.0", "@vscode/vsce": "3.2.0", "bumpp": "9.7.1", "esno": "4.8.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4ced70b..8416dce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: specifier: 22.7.9 version: 22.7.9 '@types/vscode': - specifier: 1.94.0 - version: 1.94.0 + specifier: 1.93.0 + version: 1.93.0 '@vscode/vsce': specifier: 3.2.0 version: 3.2.0 @@ -34,7 +34,7 @@ importers: version: 9.12.2 reactive-vscode: specifier: 0.2.5 - version: 0.2.5(@types/vscode@1.94.0) + version: 0.2.5(@types/vscode@1.93.0) tsup: specifier: 8.3.0 version: 8.3.0(jiti@1.21.6)(postcss@8.4.47)(tsx@4.19.1)(typescript@5.6.3) @@ -567,8 +567,8 @@ packages: '@types/node@22.7.9': resolution: {integrity: sha512-jrTfRC7FM6nChvU7X2KqcrgquofrWLFDeYC1hKfwNWomVvrn7JIksqf344WN2X/y8xrgqBd2dJATZV4GbatBfg==} - '@types/vscode@1.94.0': - resolution: {integrity: sha512-UyQOIUT0pb14XSqJskYnRwD2aG0QrPVefIfrW1djR+/J4KeFQ0i1+hjZoaAmeNf3Z2jleK+R2hv+EboG/m8ruw==} + '@types/vscode@1.93.0': + resolution: {integrity: sha512-kUK6jAHSR5zY8ps42xuW89NLcBpw1kOabah7yv38J8MyiYuOHxLQBi0e7zeXbQgVefDy/mZZetqEFC+Fl5eIEQ==} '@vitest/expect@2.1.3': resolution: {integrity: sha512-SNBoPubeCJhZ48agjXruCI57DvxcsivVDdWz+SSsmjTT4QN/DfHk3zB/xKsJqMs26bLZ/pNRLnCf0j679i0uWQ==} @@ -2331,7 +2331,7 @@ snapshots: dependencies: undici-types: 6.19.8 - '@types/vscode@1.94.0': {} + '@types/vscode@1.93.0': {} '@vitest/expect@2.1.3': dependencies: @@ -3412,10 +3412,10 @@ snapshots: strip-json-comments: 2.0.1 optional: true - reactive-vscode@0.2.5(@types/vscode@1.94.0): + reactive-vscode@0.2.5(@types/vscode@1.93.0): dependencies: '@reactive-vscode/reactivity': 0.2.5 - '@types/vscode': 1.94.0 + '@types/vscode': 1.93.0 read@1.0.7: dependencies: diff --git a/src/hurl-variables-provider.ts b/src/hurl-variables-provider.ts index 811844b..4dc21fc 100644 --- a/src/hurl-variables-provider.ts +++ b/src/hurl-variables-provider.ts @@ -1,6 +1,7 @@ export class HurlVariablesProvider { private variables: Map> = new Map(); private inlineVariables: Map> = new Map(); + private globalVariables: Map = new Map(); public getVariablesBy(filePath: string): Record { return Object.fromEntries(this.variables.get(filePath) || new Map()); @@ -54,9 +55,22 @@ export class HurlVariablesProvider { this.inlineVariables.set(filePath, new Map(Object.entries(variables))); } + public getGlobalVariables(): Record { + return Object.fromEntries(this.globalVariables); + } + + public setGlobalVariable(name: string, value: string): void { + this.globalVariables.set(name, value); + } + + public removeGlobalVariable(name: string): void { + this.globalVariables.delete(name); + } + public getAllVariablesBy(filePath: string): Record { const envVariables = this.getVariablesBy(filePath); const inlineVariables = this.getInlineVariablesBy(filePath); - return { ...envVariables, ...inlineVariables }; + const globalVariables = this.getGlobalVariables(); + return { ...envVariables, ...globalVariables, ...inlineVariables }; } } diff --git a/src/hurl-variables-tree-provider.ts b/src/hurl-variables-tree-provider.ts index b931dbe..87ab59c 100644 --- a/src/hurl-variables-tree-provider.ts +++ b/src/hurl-variables-tree-provider.ts @@ -57,6 +57,7 @@ export class HurlVariablesTreeProvider const envVariables = this.hurlVariablesProvider.getVariablesBy(filePath); const inlineVariables = this.hurlVariablesProvider.getInlineVariablesBy(filePath); + const globalVariables = this.hurlVariablesProvider.getGlobalVariables(); if (this.envFile) { const envFileVariables = await this.loadEnvFileVariables(this.envFile); @@ -124,6 +125,27 @@ export class HurlVariablesTreeProvider ), ); } + + if (Object.keys(globalVariables).length > 0) { + const globalItems = Object.entries(globalVariables).map( + ([key, value]) => + new VariableItem( + key, + value, + vscode.TreeItemCollapsibleState.None, + "globalVariable", + ), + ); + rootItems.push( + new VariableItem( + "Captured Variables", + "", + vscode.TreeItemCollapsibleState.Expanded, + "category", + globalItems, + ), + ); + } } return rootItems; } diff --git a/src/index.ts b/src/index.ts index 88de7e1..357baa9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,7 +7,11 @@ import { HurlCodeLensProvider } from "./hurl-code-lens-provider"; import { parseHurlOutput } from "./hurl-parser"; import { HurlVariablesProvider } from "./hurl-variables-provider"; import { HurlVariablesTreeProvider } from "./hurl-variables-tree-provider"; -import { chooseEnvFile, manageEnvVariables } from "./manage-variables"; +import { + chooseEnvFile, + manageEnvVariables, + saveCapturedValues, +} from "./manage-variables"; import { type LastResponseInfo, executeHurl, @@ -221,6 +225,19 @@ const { activate, deactivate } = defineExtension(() => { resultPanel.reveal(vscode.ViewColumn.Two); }; + const saveCapturedValuesFromLastResponse = ( + stderr: string, + stdout: string, + ) => { + const parsedOutput = parseHurlOutput(stderr, stdout); + for (const entry of parsedOutput.entries) { + const captures = entry.captures ?? {}; + if (Object.keys(captures).length > 0) { + saveCapturedValues(hurlVariablesProvider, captures); + } + } + }; + // Run hurl at the current line useCommand(commands.runHurl, async (lineNumber?: number) => { const runHurlCommand = async (entryNumber?: number) => { @@ -267,6 +284,7 @@ const { activate, deactivate } = defineExtension(() => { }); showResultInWebView(result); + saveCapturedValuesFromLastResponse(result.stderr, result.stdout); } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; @@ -321,6 +339,7 @@ const { activate, deactivate } = defineExtension(() => { }); showResultInWebView(result); + saveCapturedValuesFromLastResponse(result.stderr, result.stdout); } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; @@ -367,6 +386,7 @@ const { activate, deactivate } = defineExtension(() => { }); showResultInWebView(result); + saveCapturedValuesFromLastResponse(result.stderr, result.stdout); } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; @@ -505,6 +525,7 @@ const { activate, deactivate } = defineExtension(() => { }); showResultInWebView(result); + saveCapturedValuesFromLastResponse(result.stderr, result.stdout); } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; @@ -594,6 +615,16 @@ const { activate, deactivate } = defineExtension(() => { } }); + useCommand(commands.removeGlobalVariable, async (item) => { + if (item.contextValue === "globalVariable") { + hurlVariablesProvider.removeGlobalVariable(item.label); + hurlVariablesTreeProvider.refresh(); + vscode.window.showInformationMessage( + `Removed global variable: ${item.label}`, + ); + } + }); + return { dispose: () => { if (resultPanel) { diff --git a/src/manage-variables.ts b/src/manage-variables.ts index 077f4f1..4a395ae 100644 --- a/src/manage-variables.ts +++ b/src/manage-variables.ts @@ -2,6 +2,7 @@ import * as fs from "node:fs/promises"; import * as path from "node:path"; import * as vscode from "vscode"; +import { config } from "./config"; import type { HurlVariablesProvider } from "./hurl-variables-provider"; import { logger } from "./utils"; @@ -361,3 +362,15 @@ async function removeInlineVariable( ); } } + +export async function saveCapturedValues( + hurlVariablesProvider: HurlVariablesProvider, + captures: Record, +): Promise { + if (config.captureToGlobalVariable) { + for (const [key, value] of Object.entries(captures)) { + hurlVariablesProvider.setGlobalVariable(key, value); + logger.info(`Captured value set as global variable: ${key} = ${value}`); + } + } +}