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 { ControlOperator, parse, ParseEntry } from 'shell-quote';
import type { Context, Environment, Folder, HttpRequest, HttpUrlParameter, PluginDefinition, Workspace } from '@yaakapp/api';
import type { ControlOperator, ParseEntry } from 'shell-quote';
import { parse } from 'shell-quote';
type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>;
@@ -40,6 +41,7 @@ export const plugin: PluginDefinition = {
name: 'cURL',
description: 'Import cURL commands',
onImport(_ctx: Context, args: { text: string }) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return convertCurl(args.text) as any;
},
},
@@ -177,19 +179,15 @@ function importCommand(parseEntries: ParseEntry[], workspaceId: string) {
// Build the request //
// ~~~~~~~~~~~~~~~~~ //
// Url and Parameters
let urlParameters: HttpUrlParameter[];
let url: string;
const urlArg = getPairValue(flagsByName, (singletons[0] as string) || '', ['url']);
const [baseUrl, search] = splitOnce(urlArg, '?');
urlParameters =
const urlParameters: HttpUrlParameter[] =
search?.split('&').map((p) => {
const v = splitOnce(p, '=');
return { name: decodeURIComponent(v[0] ?? ''), value: decodeURIComponent(v[1] ?? ''), enabled: true };
}) ?? [];
url = baseUrl ?? urlArg;
const url = baseUrl ?? urlArg;
// Query params
for (const p of flagsByName['url-query'] ?? []) {
@@ -375,7 +373,7 @@ interface DataParameter {
}
function pairsToDataParameters(keyedPairs: FlagsByName): DataParameter[] {
let dataParameters: DataParameter[] = [];
const dataParameters: DataParameter[] = [];
for (const flagName of DATA_FLAGS) {
const pairs = keyedPairs[flagName];
@@ -386,9 +384,9 @@ function pairsToDataParameters(keyedPairs: FlagsByName): DataParameter[] {
for (const p of pairs) {
if (typeof p !== 'string') continue;
let params = p.split("&");
const params = p.split("&");
for (const param of params) {
const [name, value] = param.split('=');
const [name, value] = splitOnce(param, '=');
if (param.startsWith('@')) {
// Yaak doesn't support files in url-encoded data, so
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 { convertCurl } from '../src';
@@ -221,20 +221,20 @@ describe('importer-curl', () => {
});
test('Imports post data into URL', () => {
expect(
convertCurl('curl -G https://api.stripe.com/v1/payment_links -d limit=3'),
).toEqual({
expect(convertCurl('curl -G https://api.stripe.com/v1/payment_links -d limit=3')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
method: 'GET',
url: 'https://api.stripe.com/v1/payment_links',
urlParameters: [{
enabled: true,
name: 'limit',
value: '3',
}],
urlParameters: [
{
enabled: true,
name: 'limit',
value: '3',
},
],
}),
],
},
@@ -243,7 +243,9 @@ describe('importer-curl', () => {
test('Imports multi-line JSON', () => {
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({
resources: {
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>> = {};