From 668f92a55228dd7200b200af93d7b24219befce3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:23:58 +0000 Subject: [PATCH 1/5] Initial plan From da82958fc22acba803d54d079c70db7b8081f3d7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:30:34 +0000 Subject: [PATCH 2/5] Implement PowerShell share improvements with here-string format Co-authored-by: MathiasVDA <15101339+MathiasVDA@users.noreply.github.com> --- dev/test-powershell-share.html | 155 +++++++++++++++++++++ packages/yasqe/src/__tests__/share-test.ts | 32 ++++- packages/yasqe/src/sparql.ts | 40 +++++- 3 files changed, 222 insertions(+), 5 deletions(-) create mode 100644 dev/test-powershell-share.html diff --git a/dev/test-powershell-share.html b/dev/test-powershell-share.html new file mode 100644 index 0000000..64bfc7b --- /dev/null +++ b/dev/test-powershell-share.html @@ -0,0 +1,155 @@ + + + + + + Test PowerShell Share + + + +

PowerShell Share Format Test

+

This page tests the new PowerShell share format with multi-line query and sparql-generated output file.

+ +
+ + +
+
+ + + + diff --git a/packages/yasqe/src/__tests__/share-test.ts b/packages/yasqe/src/__tests__/share-test.ts index 1ff2ce4..3d87f11 100644 --- a/packages/yasqe/src/__tests__/share-test.ts +++ b/packages/yasqe/src/__tests__/share-test.ts @@ -105,7 +105,7 @@ describe("Share Functionality", () => { " }", ' ContentType = "application/x-www-form-urlencoded"', ' Body = "query=SELECT"', - ' OutFile = "result.json"', + ' OutFile = "sparql-generated.json"', "}", "", "Invoke-WebRequest @params", @@ -117,6 +117,36 @@ describe("Share Functionality", () => { expect(psString).to.include("Headers"); expect(psString).to.include("OutFile"); expect(psString).to.include("Accept"); + expect(psString).to.include("sparql-generated"); + }); + + it("should format PowerShell commands with here-string for query", () => { + const query = "SELECT * WHERE { ?s ?p ?o }"; + const lines = [ + '$query = @"', + query, + '"@', + "", + "$params = @{", + ' Uri = "https://example.com/sparql"', + ' Method = "Post"', + " Headers = @{", + ' "Accept" = "application/sparql-results+json"', + " }", + ' ContentType = "application/x-www-form-urlencoded"', + ' Body = "query=$query"', + ' OutFile = "sparql-generated.json"', + "}", + "", + "Invoke-WebRequest @params", + ]; + const psString = lines.join("\n"); + + expect(psString).to.include('$query = @"'); + expect(psString).to.include('"@'); + expect(psString).to.include(query); + expect(psString).to.include('Body = "query=$query"'); + expect(psString).to.include("sparql-generated"); }); it("should format wget commands with proper line breaks", () => { diff --git a/packages/yasqe/src/sparql.ts b/packages/yasqe/src/sparql.ts index 13a6513..6bdb4cc 100644 --- a/packages/yasqe/src/sparql.ts +++ b/packages/yasqe/src/sparql.ts @@ -520,10 +520,42 @@ export function getAsPowerShellString(yasqe: Yasqe, _config?: Config["requestCon lines.push(headersLines.join("\n")); lines.push(" }"); } - lines.push(` OutFile = "result.${fileExtension}"`); + lines.push(` OutFile = "sparql-generated.${fileExtension}"`); lines.push("}"); } else if (ajaxConfig.reqMethod === "POST") { - const body = queryString.stringify(ajaxConfig.args); + // Extract the query/update parameter and other parameters separately + const queryParam = ajaxConfig.args.query || ajaxConfig.args.update; + const otherArgs: RequestArgs = {}; + for (const key in ajaxConfig.args) { + if (key !== "query" && key !== "update") { + otherArgs[key] = ajaxConfig.args[key]; + } + } + + // Determine the query parameter name + const queryParamName = ajaxConfig.args.query !== undefined ? "query" : "update"; + + // Build the query string using here-string for easy editing + if (queryParam) { + // Handle both string and string[] cases + const queryText = Array.isArray(queryParam) ? queryParam[0] : queryParam; + lines.push(`$${queryParamName} = @"`); + lines.push(queryText); + lines.push(`"@`); + lines.push(""); + } + + // Build the body with the query variable and any other parameters + const bodyParts: string[] = []; + if (queryParam) { + bodyParts.push(`${queryParamName}=$${queryParamName}`); + } + if (Object.keys(otherArgs).length > 0) { + const otherArgsString = queryString.stringify(otherArgs); + bodyParts.push(otherArgsString); + } + const body = bodyParts.join("&"); + lines.push("$params = @{"); lines.push(` Uri = "${escapePowerShellString(url)}"`); lines.push(` Method = "Post"`); @@ -534,7 +566,7 @@ export function getAsPowerShellString(yasqe: Yasqe, _config?: Config["requestCon } lines.push(` ContentType = "application/x-www-form-urlencoded"`); lines.push(` Body = "${escapePowerShellString(body)}"`); - lines.push(` OutFile = "result.${fileExtension}"`); + lines.push(` OutFile = "sparql-generated.${fileExtension}"`); lines.push("}"); } else { // Handle other methods (PUT, DELETE, etc.) @@ -552,7 +584,7 @@ export function getAsPowerShellString(yasqe: Yasqe, _config?: Config["requestCon lines.push(` ContentType = "application/x-www-form-urlencoded"`); lines.push(` Body = "${body.replace(/"/g, '`"')}"`); } - lines.push(` OutFile = "result.${fileExtension}"`); + lines.push(` OutFile = "sparql-generated.${fileExtension}"`); lines.push("}"); } From b4d7e687166706ca83f2c7217081109e1517e239 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:33:30 +0000 Subject: [PATCH 3/5] Address code review feedback - eliminate duplication in parameter name logic Co-authored-by: MathiasVDA <15101339+MathiasVDA@users.noreply.github.com> --- packages/yasqe/src/sparql.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/yasqe/src/sparql.ts b/packages/yasqe/src/sparql.ts index 6bdb4cc..967edcc 100644 --- a/packages/yasqe/src/sparql.ts +++ b/packages/yasqe/src/sparql.ts @@ -524,7 +524,10 @@ export function getAsPowerShellString(yasqe: Yasqe, _config?: Config["requestCon lines.push("}"); } else if (ajaxConfig.reqMethod === "POST") { // Extract the query/update parameter and other parameters separately - const queryParam = ajaxConfig.args.query || ajaxConfig.args.update; + // Determine the query parameter name first (query takes precedence over update) + const queryParamName = ajaxConfig.args.query !== undefined ? "query" : "update"; + const queryParam = ajaxConfig.args[queryParamName]; + const otherArgs: RequestArgs = {}; for (const key in ajaxConfig.args) { if (key !== "query" && key !== "update") { @@ -532,12 +535,9 @@ export function getAsPowerShellString(yasqe: Yasqe, _config?: Config["requestCon } } - // Determine the query parameter name - const queryParamName = ajaxConfig.args.query !== undefined ? "query" : "update"; - // Build the query string using here-string for easy editing if (queryParam) { - // Handle both string and string[] cases + // Handle both string and string[] cases - use first element if array const queryText = Array.isArray(queryParam) ? queryParam[0] : queryParam; lines.push(`$${queryParamName} = @"`); lines.push(queryText); From afd58a159515cfa0778ffba8542833301a99fe0d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 15:29:17 +0000 Subject: [PATCH 4/5] Fix PowerShell variable expansion by not escaping $query in Body parameter Co-authored-by: MathiasVDA <15101339+MathiasVDA@users.noreply.github.com> --- packages/yasqe/src/__tests__/share-test.ts | 1 + packages/yasqe/src/sparql.ts | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/yasqe/src/__tests__/share-test.ts b/packages/yasqe/src/__tests__/share-test.ts index 3d87f11..36abe3b 100644 --- a/packages/yasqe/src/__tests__/share-test.ts +++ b/packages/yasqe/src/__tests__/share-test.ts @@ -146,6 +146,7 @@ describe("Share Functionality", () => { expect(psString).to.include('"@'); expect(psString).to.include(query); expect(psString).to.include('Body = "query=$query"'); + expect(psString).to.not.include('Body = "query=`$query"'); // Should NOT escape the variable expect(psString).to.include("sparql-generated"); }); diff --git a/packages/yasqe/src/sparql.ts b/packages/yasqe/src/sparql.ts index 967edcc..daeb728 100644 --- a/packages/yasqe/src/sparql.ts +++ b/packages/yasqe/src/sparql.ts @@ -546,15 +546,20 @@ export function getAsPowerShellString(yasqe: Yasqe, _config?: Config["requestCon } // Build the body with the query variable and any other parameters - const bodyParts: string[] = []; - if (queryParam) { - bodyParts.push(`${queryParamName}=$${queryParamName}`); - } - if (Object.keys(otherArgs).length > 0) { + // Note: We don't escape the variable reference itself, only the other args + let bodyExpression: string; + if (queryParam && Object.keys(otherArgs).length > 0) { + // Both query variable and other args + const otherArgsString = queryString.stringify(otherArgs); + bodyExpression = `"${queryParamName}=$${queryParamName}&${escapePowerShellString(otherArgsString)}"`; + } else if (queryParam) { + // Only query variable + bodyExpression = `"${queryParamName}=$${queryParamName}"`; + } else { + // Only other args (shouldn't happen, but handle it) const otherArgsString = queryString.stringify(otherArgs); - bodyParts.push(otherArgsString); + bodyExpression = `"${escapePowerShellString(otherArgsString)}"`; } - const body = bodyParts.join("&"); lines.push("$params = @{"); lines.push(` Uri = "${escapePowerShellString(url)}"`); @@ -565,7 +570,7 @@ export function getAsPowerShellString(yasqe: Yasqe, _config?: Config["requestCon lines.push(" }"); } lines.push(` ContentType = "application/x-www-form-urlencoded"`); - lines.push(` Body = "${escapePowerShellString(body)}"`); + lines.push(` Body = ${bodyExpression}`); lines.push(` OutFile = "sparql-generated.${fileExtension}"`); lines.push("}"); } else { From 4ef7e5138e2acbbb64c5773435fdbbd0457b0a2d Mon Sep 17 00:00:00 2001 From: Mathias Vanden Auweele Date: Thu, 12 Feb 2026 18:25:10 +0100 Subject: [PATCH 5/5] fix: needs to be url encoded --- packages/yasqe/src/__tests__/share-test.ts | 4 ++-- packages/yasqe/src/sparql.ts | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/yasqe/src/__tests__/share-test.ts b/packages/yasqe/src/__tests__/share-test.ts index 36abe3b..c8d17d8 100644 --- a/packages/yasqe/src/__tests__/share-test.ts +++ b/packages/yasqe/src/__tests__/share-test.ts @@ -134,7 +134,7 @@ describe("Share Functionality", () => { ' "Accept" = "application/sparql-results+json"', " }", ' ContentType = "application/x-www-form-urlencoded"', - ' Body = "query=$query"', + ' Body = "query=$([System.Net.WebUtility]::UrlEncode($query))"', ' OutFile = "sparql-generated.json"', "}", "", @@ -145,7 +145,7 @@ describe("Share Functionality", () => { expect(psString).to.include('$query = @"'); expect(psString).to.include('"@'); expect(psString).to.include(query); - expect(psString).to.include('Body = "query=$query"'); + expect(psString).to.include('Body = "query=$([System.Net.WebUtility]::UrlEncode($query))"'); expect(psString).to.not.include('Body = "query=`$query"'); // Should NOT escape the variable expect(psString).to.include("sparql-generated"); }); diff --git a/packages/yasqe/src/sparql.ts b/packages/yasqe/src/sparql.ts index daeb728..6ac7e60 100644 --- a/packages/yasqe/src/sparql.ts +++ b/packages/yasqe/src/sparql.ts @@ -546,15 +546,16 @@ export function getAsPowerShellString(yasqe: Yasqe, _config?: Config["requestCon } // Build the body with the query variable and any other parameters - // Note: We don't escape the variable reference itself, only the other args + // The query must be URL-encoded for application/x-www-form-urlencoded let bodyExpression: string; + const urlEncodeExpr = `[System.Net.WebUtility]::UrlEncode($${queryParamName})`; if (queryParam && Object.keys(otherArgs).length > 0) { // Both query variable and other args const otherArgsString = queryString.stringify(otherArgs); - bodyExpression = `"${queryParamName}=$${queryParamName}&${escapePowerShellString(otherArgsString)}"`; + bodyExpression = `"${queryParamName}=$(${urlEncodeExpr})&${escapePowerShellString(otherArgsString)}"`; } else if (queryParam) { - // Only query variable - bodyExpression = `"${queryParamName}=$${queryParamName}"`; + // Only query variable - use subexpression for URL encoding + bodyExpression = `"${queryParamName}=$(${urlEncodeExpr})"`; } else { // Only other args (shouldn't happen, but handle it) const otherArgsString = queryString.stringify(otherArgs);