diff --git a/plugins/importer-curl/src/index.ts b/plugins/importer-curl/src/index.ts index f38370f0..72f4b92a 100644 --- a/plugins/importer-curl/src/index.ts +++ b/plugins/importer-curl/src/index.ts @@ -98,8 +98,12 @@ export const plugin: PluginDefinition = { * Handles line continuations, semicolons, and newline-separated curl commands. */ function splitCommands(rawData: string): string[] { - // Join line continuations (backslash-newline, and backslash-CRLF for Windows) - const joined = rawData.replace(/\\\r?\n/g, " "); + // Join line continuations (backslash-newline, and backslash-CRLF for + // Windows). Trailing spaces or tabs after the backslash are common when a + // command is copied from a terminal or a doc, and the shell treats + // "\ " as an escaped space rather than a continuation, so accept + // them here to keep the pasted command in one piece. + const joined = rawData.replace(/\\[ \t]*\r?\n/g, " "); // Count consecutive backslashes immediately before position i. // An even count means the quote at i is NOT escaped; odd means it IS escaped. diff --git a/plugins/importer-curl/tests/index.test.ts b/plugins/importer-curl/tests/index.test.ts index d147b303..79f38198 100644 --- a/plugins/importer-curl/tests/index.test.ts +++ b/plugins/importer-curl/tests/index.test.ts @@ -142,6 +142,33 @@ describe("importer-curl", () => { }); }); + // A trailing space after the continuation backslash is invisible in most + // editors but used to stop the join, so the quoted body split across + // lines and the parser failed with "Got EOF while in a quoted string". + test("Imports line continuations with trailing whitespace after the backslash", () => { + expect( + convertCurl( + "curl -X POST https://yaak.app \\ \n -H 'Content-Type: application/json' \\\t\n --data '{\"a\":1}' \\ \r\n -H 'Accept: application/json'", + ), + ).toEqual({ + resources: { + workspaces: [baseWorkspace()], + httpRequests: [ + baseRequest({ + url: "https://yaak.app", + method: "POST", + headers: [ + { name: "Content-Type", value: "application/json", enabled: true }, + { name: "Accept", value: "application/json", enabled: true }, + ], + bodyType: "application/json", + body: { text: '{"a":1}' }, + }), + ], + }, + }); + }); + test("Imports with Windows CRLF line endings", () => { expect(convertCurl("curl \\\r\n -X POST \\\r\n https://yaak.app")).toEqual({ resources: {