Update plugins

This commit is contained in:
Gregory Schier
2025-01-20 13:07:04 -08:00
parent 26cce077bb
commit d142966d0c
16 changed files with 855 additions and 504 deletions

1096
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -19,6 +19,6 @@
"workspaces-run": "^1.0.2"
},
"dependencies": {
"@yaakapp/api": "^0.3.2"
"@yaakapp/api": "^0.3.4"
}
}

View File

@@ -1,4 +1,4 @@
import { Context, HttpRequest, PluginDefinition } from '@yaakapp/api';
import { HttpRequest, PluginDefinition } from '@yaakapp/api';
const NEWLINE = '\\\n ';
@@ -9,14 +9,14 @@ export const plugin: PluginDefinition = {
icon: 'copy',
async onSelect(ctx, args) {
const rendered_request = await ctx.httpRequest.render({ httpRequest: args.httpRequest, purpose: 'preview' });
const data = await pluginHookExport(ctx, rendered_request);
const data = await convertToCurl(rendered_request);
ctx.clipboard.copyText(data);
ctx.toast.show({ message: 'Curl copied to clipboard', icon: 'copy' });
},
}],
};
export async function pluginHookExport(_ctx: Context, request: Partial<HttpRequest>) {
export async function convertToCurl(request: Partial<HttpRequest>) {
const xs = ['curl'];
// Add method and URL all on first line

View File

@@ -1,13 +1,10 @@
import { describe, expect, test } from 'vitest';
import { Context } from '@yaakapp/api';
import { pluginHookExport } from '../src';
const ctx = {} as Context;
import { convertToCurl } from '../src';
describe('exporter-curl', () => {
test('Exports GET with params', async () => {
expect(
await pluginHookExport(ctx, {
await convertToCurl({
url: 'https://yaak.app',
urlParameters: [
{ name: 'a', value: 'aaa' },
@@ -21,7 +18,7 @@ describe('exporter-curl', () => {
});
test('Exports POST with url form data', async () => {
expect(
await pluginHookExport(ctx, {
await convertToCurl({
url: 'https://yaak.app',
method: 'POST',
bodyType: 'application/x-www-form-urlencoded',
@@ -40,12 +37,12 @@ describe('exporter-curl', () => {
test('Exports POST with GraphQL data', async () => {
expect(
await pluginHookExport(ctx, {
await convertToCurl({
url: 'https://yaak.app',
method: 'POST',
bodyType: 'graphql',
body: {
query : '{foo,bar}',
query: '{foo,bar}',
variables: '{"a": "aaa", "b": "bbb"}',
},
}),
@@ -56,12 +53,12 @@ describe('exporter-curl', () => {
test('Exports POST with GraphQL data no variables', async () => {
expect(
await pluginHookExport(ctx, {
await convertToCurl({
url: 'https://yaak.app',
method: 'POST',
bodyType: 'graphql',
body: {
query : '{foo,bar}',
query: '{foo,bar}',
},
}),
).toEqual(
@@ -71,7 +68,7 @@ describe('exporter-curl', () => {
test('Exports PUT with multipart form', async () => {
expect(
await pluginHookExport(ctx, {
await convertToCurl({
url: 'https://yaak.app',
method: 'PUT',
bodyType: 'multipart/form-data',
@@ -96,7 +93,7 @@ describe('exporter-curl', () => {
test('Exports JSON body', async () => {
expect(
await pluginHookExport(ctx, {
await convertToCurl({
url: 'https://yaak.app',
method: 'POST',
bodyType: 'application/json',
@@ -116,7 +113,7 @@ describe('exporter-curl', () => {
test('Exports multi-line JSON body', async () => {
expect(
await pluginHookExport(ctx, {
await convertToCurl({
url: 'https://yaak.app',
method: 'POST',
bodyType: 'application/json',
@@ -136,7 +133,7 @@ describe('exporter-curl', () => {
test('Exports headers', async () => {
expect(
await pluginHookExport(ctx, {
await convertToCurl({
headers: [
{ name: 'a', value: 'aaa' },
{ name: 'b', value: 'bbb', enabled: true },
@@ -148,7 +145,7 @@ describe('exporter-curl', () => {
test('Basic auth', async () => {
expect(
await pluginHookExport(ctx, {
await convertToCurl({
url: 'https://yaak.app',
authenticationType: 'basic',
authentication: {
@@ -161,7 +158,7 @@ describe('exporter-curl', () => {
test('Broken basic auth', async () => {
expect(
await pluginHookExport(ctx, {
await convertToCurl({
url: 'https://yaak.app',
authenticationType: 'basic',
authentication: {},
@@ -171,7 +168,7 @@ describe('exporter-curl', () => {
test('Digest auth', async () => {
expect(
await pluginHookExport(ctx, {
await convertToCurl({
url: 'https://yaak.app',
authenticationType: 'digest',
authentication: {
@@ -184,7 +181,7 @@ describe('exporter-curl', () => {
test('Bearer auth', async () => {
expect(
await pluginHookExport(ctx, {
await convertToCurl({
url: 'https://yaak.app',
authenticationType: 'bearer',
authentication: {
@@ -196,7 +193,7 @@ describe('exporter-curl', () => {
test('Broken bearer auth', async () => {
expect(
await pluginHookExport(ctx, {
await convertToCurl({
url: 'https://yaak.app',
authenticationType: 'bearer',
authentication: {

View File

@@ -1,8 +1,14 @@
import { Context } from '@yaakapp/api';
import { PluginDefinition } from '@yaakapp/api';
import { JSONPath } from 'jsonpath-plus';
export function pluginHookResponseFilter(_ctx: Context, args: { filter: string; body: string }) {
const parsed = JSON.parse(args.body);
const filtered = JSONPath({ path: args.filter, json: parsed });
return JSON.stringify(filtered, null, 2);
}
export const plugin: PluginDefinition = {
filter: {
name: 'JSONPath',
description: 'Filter JSONPath',
onFilter(_ctx, args) {
const parsed = JSON.parse(args.payload);
const filtered = JSONPath({ path: args.filter, json: parsed });
return { filtered: JSON.stringify(filtered, null, 2) };
},
},
};

View File

@@ -1,17 +1,21 @@
import { DOMParser } from '@xmldom/xmldom';
import { Context } from '@yaakapp/api';
import { PluginDefinition } from '@yaakapp/api';
import xpath from 'xpath';
export function pluginHookResponseFilter(
_ctx: Context,
{ filter, body }: { filter: string; body: string },
) {
const doc = new DOMParser().parseFromString(body, 'text/xml');
const result = xpath.select(filter, doc, false);
if (Array.isArray(result)) {
return result.map(r => String(r)).join('\n');
} else {
// Not sure what cases this happens in (?)
return String(result);
}
}
export const plugin: PluginDefinition = {
filter: {
name: 'XPath',
description: 'Filter XPath',
onFilter(_ctx, args) {
const doc = new DOMParser().parseFromString(args.payload, 'text/xml');
const result = xpath.select(args.filter, doc, false);
if (Array.isArray(result)) {
return { filtered: result.map(r => String(r)).join('\n') };
} else {
// Not sure what cases this happens in (?)
return { filtered: String(result) };
}
},
},
};

View File

@@ -1,4 +1,4 @@
import { Context, Environment, Folder, HttpRequest, HttpUrlParameter, Workspace } from '@yaakapp/api';
import { Context, Environment, Folder, HttpRequest, HttpUrlParameter, PluginDefinition, Workspace } from '@yaakapp/api';
import { ControlOperator, parse, ParseEntry } from 'shell-quote';
type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>;
@@ -35,7 +35,17 @@ type FlagValue = string | boolean;
type FlagsByName = Record<string, FlagValue[]>;
export function pluginHookImport(_ctx: Context, rawData: string) {
export const plugin: PluginDefinition = {
importer: {
name: 'cURL',
description: 'Import cURL commands',
onImport(_ctx: Context, args: { text: string }) {
return convertCurl(args.text) as any;
},
},
};
export function convertCurl(rawData: string) {
if (!rawData.match(/^\s*curl /)) {
return null;
}

View File

@@ -1,12 +1,10 @@
import { Context, HttpRequest, Workspace } from '@yaakapp/api';
import { HttpRequest, Workspace } from '@yaakapp/api';
import { describe, expect, test } from 'vitest';
import { pluginHookImport } from '../src';
const ctx = {} as Context;
import { convertCurl } from '../src';
describe('importer-curl', () => {
test('Imports basic GET', () => {
expect(pluginHookImport(ctx, 'curl https://yaak.app')).toEqual({
expect(convertCurl('curl https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
@@ -19,7 +17,7 @@ describe('importer-curl', () => {
});
test('Explicit URL', () => {
expect(pluginHookImport(ctx, 'curl --url https://yaak.app')).toEqual({
expect(convertCurl('curl --url https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
@@ -32,7 +30,7 @@ describe('importer-curl', () => {
});
test('Missing URL', () => {
expect(pluginHookImport(ctx, 'curl -X POST')).toEqual({
expect(convertCurl('curl -X POST')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
@@ -45,7 +43,7 @@ describe('importer-curl', () => {
});
test('URL between', () => {
expect(pluginHookImport(ctx, 'curl -v https://yaak.app -X POST')).toEqual({
expect(convertCurl('curl -v https://yaak.app -X POST')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
@@ -59,7 +57,7 @@ describe('importer-curl', () => {
});
test('Random flags', () => {
expect(pluginHookImport(ctx, 'curl --random -Z -Y -S --foo https://yaak.app')).toEqual({
expect(convertCurl('curl --random -Z -Y -S --foo https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
@@ -72,7 +70,7 @@ describe('importer-curl', () => {
});
test('Imports --request method', () => {
expect(pluginHookImport(ctx, 'curl --request POST https://yaak.app')).toEqual({
expect(convertCurl('curl --request POST https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
@@ -86,7 +84,7 @@ describe('importer-curl', () => {
});
test('Imports -XPOST method', () => {
expect(pluginHookImport(ctx, 'curl -XPOST --request POST https://yaak.app')).toEqual({
expect(convertCurl('curl -XPOST --request POST https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
@@ -101,10 +99,7 @@ describe('importer-curl', () => {
test('Imports multiple requests', () => {
expect(
pluginHookImport(
ctx,
'curl \\\n https://yaak.app\necho "foo"\ncurl example.com;curl foo.com',
),
convertCurl('curl \\\n https://yaak.app\necho "foo"\ncurl example.com;curl foo.com'),
).toEqual({
resources: {
workspaces: [baseWorkspace()],
@@ -119,7 +114,7 @@ describe('importer-curl', () => {
test('Imports form data', () => {
expect(
pluginHookImport(ctx, 'curl -X POST -F "a=aaa" -F b=bbb" -F f=@filepath https://yaak.app'),
convertCurl('curl -X POST -F "a=aaa" -F b=bbb" -F f=@filepath https://yaak.app'),
).toEqual({
resources: {
workspaces: [baseWorkspace()],
@@ -149,7 +144,7 @@ describe('importer-curl', () => {
});
test('Imports data params as form url-encoded', () => {
expect(pluginHookImport(ctx, 'curl -d a -d b -d c=ccc https://yaak.app')).toEqual({
expect(convertCurl('curl -d a -d b -d c=ccc https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
@@ -179,7 +174,7 @@ describe('importer-curl', () => {
test('Imports data params as text', () => {
expect(
pluginHookImport(ctx, 'curl -H Content-Type:text/plain -d a -d b -d c=ccc https://yaak.app'),
convertCurl('curl -H Content-Type:text/plain -d a -d b -d c=ccc https://yaak.app'),
).toEqual({
resources: {
workspaces: [baseWorkspace()],
@@ -198,7 +193,7 @@ describe('importer-curl', () => {
test('Imports post data into URL', () => {
expect(
pluginHookImport(ctx, 'curl -G https://api.stripe.com/v1/payment_links -d limit=3'),
convertCurl('curl -G https://api.stripe.com/v1/payment_links -d limit=3'),
).toEqual({
resources: {
workspaces: [baseWorkspace()],
@@ -210,7 +205,7 @@ describe('importer-curl', () => {
enabled: true,
name: 'limit',
value: '3',
}]
}],
}),
],
},
@@ -219,10 +214,7 @@ describe('importer-curl', () => {
test('Imports multi-line JSON', () => {
expect(
pluginHookImport(
ctx,
`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()],
@@ -241,7 +233,7 @@ describe('importer-curl', () => {
test('Imports multiple headers', () => {
expect(
pluginHookImport(ctx, 'curl -H Foo:bar --header Name -H AAA:bbb -H :ccc https://yaak.app'),
convertCurl('curl -H Foo:bar --header Name -H AAA:bbb -H :ccc https://yaak.app'),
).toEqual({
resources: {
workspaces: [baseWorkspace()],
@@ -261,7 +253,7 @@ describe('importer-curl', () => {
});
test('Imports basic auth', () => {
expect(pluginHookImport(ctx, 'curl --user user:pass https://yaak.app')).toEqual({
expect(convertCurl('curl --user user:pass https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
@@ -279,7 +271,7 @@ describe('importer-curl', () => {
});
test('Imports digest auth', () => {
expect(pluginHookImport(ctx, 'curl --digest --user user:pass https://yaak.app')).toEqual({
expect(convertCurl('curl --digest --user user:pass https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
@@ -297,7 +289,7 @@ describe('importer-curl', () => {
});
test('Imports cookie as header', () => {
expect(pluginHookImport(ctx, 'curl --cookie "foo=bar" https://yaak.app')).toEqual({
expect(convertCurl('curl --cookie "foo=bar" https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
@@ -311,7 +303,7 @@ describe('importer-curl', () => {
});
test('Imports query params', () => {
expect(pluginHookImport(ctx, 'curl "https://yaak.app" --url-query foo=bar --url-query baz=qux')).toEqual({
expect(convertCurl('curl "https://yaak.app" --url-query foo=bar --url-query baz=qux')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
@@ -328,7 +320,7 @@ describe('importer-curl', () => {
});
test('Imports query params from the URL', () => {
expect(pluginHookImport(ctx, 'curl "https://yaak.app?foo=bar&baz=a%20a"')).toEqual({
expect(convertCurl('curl "https://yaak.app?foo=bar&baz=a%20a"')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [

View File

@@ -1,4 +1,4 @@
import { Context, Environment, Folder, GrpcRequest, HttpRequest, Workspace } from '@yaakapp/api';
import { Context, Environment, Folder, GrpcRequest, HttpRequest, PluginDefinition, Workspace } from '@yaakapp/api';
import YAML from 'yaml';
type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>;
@@ -11,7 +11,17 @@ export interface ExportResources {
folders: AtLeast<Folder, 'name' | 'id' | 'model' | 'workspaceId'>[];
}
export function pluginHookImport(ctx: Context, contents: string) {
export const plugin: PluginDefinition = {
importer: {
name: 'Insomnia',
description: 'Import Insomnia workspaces',
onImport(_ctx: Context, args: { text: string }) {
return convertInsomnia(args.text) as any;
},
},
};
export function convertInsomnia(contents: string) {
let parsed: any;
try {

View File

@@ -1,10 +1,7 @@
import { Context } from '@yaakapp/api';
import * as fs from 'node:fs';
import * as path from 'node:path';
import { describe, expect, test } from 'vitest';
import { pluginHookImport } from '../src';
const ctx = {} as Context;
import { convertInsomnia } from '../src';
describe('importer-yaak', () => {
const p = path.join(__dirname, 'fixtures');
@@ -18,7 +15,7 @@ describe('importer-yaak', () => {
test('Imports ' + fixture, () => {
const contents = fs.readFileSync(path.join(p, fixture), 'utf-8');
const expected = fs.readFileSync(path.join(p, fixture.replace('.input', '.output')), 'utf-8');
const result = pluginHookImport(ctx, contents);
const result = convertInsomnia(contents);
// console.log(JSON.stringify(result, null, 2))
expect(result).toEqual(JSON.parse(expected));
});

View File

@@ -1,7 +1,6 @@
import { Context } from '@yaakapp/api';
import { Context, Environment, Folder, HttpRequest, PluginDefinition, Workspace } from '@yaakapp/api';
import { convert } from 'openapi-to-postmanv2';
import { pluginHookImport as pluginHookImportPostman } from '../../importer-postman/src/index';
import { Folder, HttpRequest, Workspace, Environment } from '@yaakapp/api';
import { convertPostman } from '@yaakapp/importer-postman/src';
type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>;
@@ -12,8 +11,17 @@ interface ExportResources {
folders: AtLeast<Folder, 'name' | 'id' | 'model' | 'workspaceId'>[];
}
export async function pluginHookImport(
ctx: Context,
export const plugin: PluginDefinition = {
importer: {
name: 'OpenAPI',
description: 'Import OpenAPI collections',
onImport(_ctx: Context, args: { text: string }) {
return convertOpenApi(args.text) as any;
},
},
};
export async function convertOpenApi(
contents: string,
): Promise<{ resources: ExportResources } | undefined> {
let postmanCollection;
@@ -32,5 +40,5 @@ export async function pluginHookImport(
return undefined;
}
return pluginHookImportPostman(ctx, JSON.stringify(postmanCollection));
return convertPostman(JSON.stringify(postmanCollection));
}

View File

@@ -1,24 +1,21 @@
import { Context } from '@yaakapp/api';
import * as fs from 'node:fs';
import * as path from 'node:path';
import { describe, expect, test } from 'vitest';
import { pluginHookImport } from '../src';
const ctx = {} as Context;
import { convertOpenApi } from '../src';
describe('importer-openapi', () => {
const p = path.join(__dirname, 'fixtures');
const fixtures = fs.readdirSync(p);
test('Skips invalid file', async () => {
const imported = await pluginHookImport(ctx, '{}');
const imported = await convertOpenApi('{}');
expect(imported).toBeUndefined();
})
});
for (const fixture of fixtures) {
test('Imports ' + fixture, async () => {
const contents = fs.readFileSync(path.join(p, fixture), 'utf-8');
const imported = await pluginHookImport(ctx, contents);
const imported = await convertOpenApi(contents);
expect(imported?.resources.workspaces).toEqual([
expect.objectContaining({
name: 'Swagger Petstore - OpenAPI 3.0',

View File

@@ -5,6 +5,7 @@ import {
HttpRequest,
HttpRequestHeader,
HttpUrlParameter,
PluginDefinition,
Workspace,
} from '@yaakapp/api';
@@ -21,8 +22,17 @@ interface ExportResources {
folders: AtLeast<Folder, 'name' | 'id' | 'model' | 'workspaceId'>[];
}
export function pluginHookImport(
_ctx: Context,
export const plugin: PluginDefinition = {
importer: {
name: 'Postman',
description: 'Import postman collections',
onImport(_ctx: Context, args: { text: string }) {
return convertPostman(args.text) as any;
},
},
};
export function convertPostman(
contents: string,
): { resources: ExportResources } | undefined {
const root = parseJSONToRecord(contents);

View File

@@ -1,10 +1,7 @@
import { Context } from '@yaakapp/api';
import * as fs from 'node:fs';
import * as path from 'node:path';
import { describe, expect, test } from 'vitest';
import { pluginHookImport } from '../src';
const ctx = {} as Context;
import { convertPostman } from '../src';
describe('importer-postman', () => {
const p = path.join(__dirname, 'fixtures');
@@ -18,7 +15,7 @@ describe('importer-postman', () => {
test('Imports ' + fixture, () => {
const contents = fs.readFileSync(path.join(p, fixture), 'utf-8');
const expected = fs.readFileSync(path.join(p, fixture.replace('.input', '.output')), 'utf-8');
const result = pluginHookImport(ctx, contents);
const result = convertPostman(contents);
// console.log(JSON.stringify(result, null, 2))
expect(result).toEqual(JSON.parse(expected));
});

View File

@@ -1,6 +1,16 @@
import { Context, Environment } from '@yaakapp/api';
import { Environment, PluginDefinition } from '@yaakapp/api';
export function pluginHookImport(_ctx: Context, contents: string) {
export const plugin: PluginDefinition = {
importer: {
name: 'Yaak',
description: 'Yaak official format',
onImport(_ctx, args) {
return migrateImport(args.text) as any;
},
},
};
export function migrateImport(contents: string) {
let parsed;
try {
parsed = JSON.parse(contents);

View File

@@ -1,19 +1,15 @@
import { Context } from '@yaakapp/api';
import { describe, expect, test } from 'vitest';
import { pluginHookImport } from '../src';
const ctx = {} as Context;
import { migrateImport } from '../src';
describe('importer-yaak', () => {
test('Skips invalid imports', () => {
expect(pluginHookImport(ctx, 'not JSON')).toBeUndefined();
expect(pluginHookImport(ctx, '[]')).toBeUndefined();
expect(pluginHookImport(ctx, JSON.stringify({ resources: {} }))).toBeUndefined();
expect(migrateImport('not JSON')).toBeUndefined();
expect(migrateImport('[]')).toBeUndefined();
expect(migrateImport(JSON.stringify({ resources: {} }))).toBeUndefined();
});
test('converts schema 1 to 2', () => {
const imported = pluginHookImport(
ctx,
const imported = migrateImport(
JSON.stringify({
yaakSchema: 1,
resources: {
@@ -31,8 +27,7 @@ describe('importer-yaak', () => {
);
});
test('converts schema 2 to 3', () => {
const imported = pluginHookImport(
ctx,
const imported = migrateImport(
JSON.stringify({
yaakSchema: 2,
resources: {