Gregory Schier
2025-07-10 13:13:28 -07:00
parent 456c8bd95f
commit f63da432b9
2 changed files with 46 additions and 21 deletions

View File

@@ -1,5 +1,6 @@
import { Context, Environment, Folder, HttpRequest, HttpUrlParameter, PluginDefinition, Workspace } from '@yaakapp/api'; import type { Context, Environment, Folder, HttpRequest, HttpUrlParameter, PluginDefinition, Workspace } from '@yaakapp/api';
import { ControlOperator, parse, ParseEntry } from 'shell-quote'; import type { ControlOperator, ParseEntry } from 'shell-quote';
import { parse } from 'shell-quote';
type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>; type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>;
@@ -40,6 +41,7 @@ export const plugin: PluginDefinition = {
name: 'cURL', name: 'cURL',
description: 'Import cURL commands', description: 'Import cURL commands',
onImport(_ctx: Context, args: { text: string }) { onImport(_ctx: Context, args: { text: string }) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return convertCurl(args.text) as any; return convertCurl(args.text) as any;
}, },
}, },
@@ -177,19 +179,15 @@ function importCommand(parseEntries: ParseEntry[], workspaceId: string) {
// Build the request // // Build the request //
// ~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~ //
// Url and Parameters
let urlParameters: HttpUrlParameter[];
let url: string;
const urlArg = getPairValue(flagsByName, (singletons[0] as string) || '', ['url']); const urlArg = getPairValue(flagsByName, (singletons[0] as string) || '', ['url']);
const [baseUrl, search] = splitOnce(urlArg, '?'); const [baseUrl, search] = splitOnce(urlArg, '?');
urlParameters = const urlParameters: HttpUrlParameter[] =
search?.split('&').map((p) => { search?.split('&').map((p) => {
const v = splitOnce(p, '='); const v = splitOnce(p, '=');
return { name: decodeURIComponent(v[0] ?? ''), value: decodeURIComponent(v[1] ?? ''), enabled: true }; return { name: decodeURIComponent(v[0] ?? ''), value: decodeURIComponent(v[1] ?? ''), enabled: true };
}) ?? []; }) ?? [];
url = baseUrl ?? urlArg; const url = baseUrl ?? urlArg;
// Query params // Query params
for (const p of flagsByName['url-query'] ?? []) { for (const p of flagsByName['url-query'] ?? []) {
@@ -375,7 +373,7 @@ interface DataParameter {
} }
function pairsToDataParameters(keyedPairs: FlagsByName): DataParameter[] { function pairsToDataParameters(keyedPairs: FlagsByName): DataParameter[] {
let dataParameters: DataParameter[] = []; const dataParameters: DataParameter[] = [];
for (const flagName of DATA_FLAGS) { for (const flagName of DATA_FLAGS) {
const pairs = keyedPairs[flagName]; const pairs = keyedPairs[flagName];
@@ -386,9 +384,9 @@ function pairsToDataParameters(keyedPairs: FlagsByName): DataParameter[] {
for (const p of pairs) { for (const p of pairs) {
if (typeof p !== 'string') continue; if (typeof p !== 'string') continue;
let params = p.split("&"); const params = p.split("&");
for (const param of params) { for (const param of params) {
const [name, value] = param.split('='); const [name, value] = splitOnce(param, '=');
if (param.startsWith('@')) { if (param.startsWith('@')) {
// Yaak doesn't support files in url-encoded data, so // Yaak doesn't support files in url-encoded data, so
dataParameters.push({ dataParameters.push({

View File

@@ -1,4 +1,4 @@
import { HttpRequest, Workspace } from '@yaakapp/api'; import type { HttpRequest, Workspace } from '@yaakapp/api';
import { describe, expect, test } from 'vitest'; import { describe, expect, test } from 'vitest';
import { convertCurl } from '../src'; import { convertCurl } from '../src';
@@ -221,20 +221,20 @@ describe('importer-curl', () => {
}); });
test('Imports post data into URL', () => { test('Imports post data into URL', () => {
expect( expect(convertCurl('curl -G https://api.stripe.com/v1/payment_links -d limit=3')).toEqual({
convertCurl('curl -G https://api.stripe.com/v1/payment_links -d limit=3'),
).toEqual({
resources: { resources: {
workspaces: [baseWorkspace()], workspaces: [baseWorkspace()],
httpRequests: [ httpRequests: [
baseRequest({ baseRequest({
method: 'GET', method: 'GET',
url: 'https://api.stripe.com/v1/payment_links', url: 'https://api.stripe.com/v1/payment_links',
urlParameters: [{ urlParameters: [
enabled: true, {
name: 'limit', enabled: true,
value: '3', name: 'limit',
}], value: '3',
},
],
}), }),
], ],
}, },
@@ -243,7 +243,9 @@ describe('importer-curl', () => {
test('Imports multi-line JSON', () => { test('Imports multi-line JSON', () => {
expect( expect(
convertCurl(`curl -H Content-Type:application/json -d $'{\n "foo":"bar"\n}' https://yaak.app`), convertCurl(
`curl -H Content-Type:application/json -d $'{\n "foo":"bar"\n}' https://yaak.app`,
),
).toEqual({ ).toEqual({
resources: { resources: {
workspaces: [baseWorkspace()], workspaces: [baseWorkspace()],
@@ -364,6 +366,31 @@ describe('importer-curl', () => {
}, },
}); });
}); });
test('Imports weird body', () => {
expect(convertCurl(`curl 'https://yaak.app' -X POST --data-raw 'foo=bar=baz'`)).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
url: 'https://yaak.app',
method: "POST",
bodyType: 'application/x-www-form-urlencoded',
body: {
form: [{ name: 'foo', value: 'bar=baz', enabled: true }],
},
headers: [
{
enabled: true,
name: 'Content-Type',
value: 'application/x-www-form-urlencoded',
},
],
}),
],
},
});
});
}); });
const idCount: Partial<Record<string, number>> = {}; const idCount: Partial<Record<string, number>> = {};