From e9db671ef793e36a4ccfc25add906956b619a11d Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Wed, 25 Oct 2023 14:46:34 -0700 Subject: [PATCH] feat: creation of a new `addClientPlugin` interface for target+client installation --- README.md | 39 ++++++++++++++++++++++++++++++++++----- src/targets/index.test.ts | 36 ++++++++++++++++++++++++++++++++++-- src/targets/index.ts | 9 +++++++++ 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 74f22caa1..8f9a27db9 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,13 @@ npm install --save @readme/httpsnippet ## Usage -### HTTPSnippet(source [, options]) +### HTTPSnippet(input [, options]) -#### source +#### input _Required_ Type: `object` -Name of [conversion target](https://github.com/Kong/httpsnippet/wiki/Targets) +The [HAR](http://www.softwareishard.com/blog/har-12-spec/#request) request object to generate a snippet for. ```ts import { HTTPSnippet } from 'httpsnippet'; @@ -128,13 +128,13 @@ HTTPSnippet.addTarget(customLanguageTarget); ### addTargetClient(target, client) -### Target +#### Target _Required_ Type: `string` Name of [conversion target](https://github.com/Kong/httpsnippet/wiki/Targets) -### Client +#### Client _Required_ Type: `object` @@ -145,6 +145,34 @@ import { customClient } from 'httpsnippet-for-my-node-http-client'; HTTPSnippet.addTargetClient('node', customClient); ``` +### addClientPlugin(plugin) + +#### Plugin + +_Required_ Type: `object` + +The client plugin to install. + +```ts +addClientPlugin({ + target: 'node', + client: { + info: { + key: 'custom', + title: 'Custom HTTP library', + link: 'https://example.com', + description: 'A custom HTTP library', + extname: '.custom', + }, + convert: () => { + return 'This was generated from a custom client.'; + }, + }, +}); +``` + +The above example will create a new `custom` client snippet generator for the `node` target. + ## Documentation At the heart of this module is the [HAR Format](http://www.softwareishard.com/blog/har-12-spec/#request) as the HTTP request description format, please review some of the sample JSON HAR Request objects in [test fixtures](/test/fixtures/requests), or read the [HAR Docs](http://www.softwareishard.com/blog/har-12-spec/#request) for more details. @@ -161,6 +189,7 @@ There are some major differences between this library and the [httpsnippet](http - The main `HTTPSnippet` export contains an `options` argument for an `harIsAlreadyEncoded` option for disabling [escaping](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) of cookies and query strings in URLs. - We added this because all HARs that we interact with already have this data escaped and this option prevents them from being double encoded, thus corrupting the data. - Does not support the `insecureSkipVerify` option on `go:native`, `node:native`, `ruby:native`, and `shell:curl` as we don't want snippets generated for our users to bypass SSL certificate verification. +- Includes a full plugin system, `#addClientPlugin`, for quick installation of a target client. - Node - `fetch` - Body payloads are treated as an object literal and wrapped within `JSON.stringify()`. We do this to keep those targets looking nicer with those kinds of payloads. This also applies to the JS `fetch` target as well. diff --git a/src/targets/index.test.ts b/src/targets/index.test.ts index a58fcf5d2..4f3f66b28 100644 --- a/src/targets/index.test.ts +++ b/src/targets/index.test.ts @@ -1,4 +1,4 @@ -import type { Client, ClientId, Target, TargetId } from './index.js'; +import type { Client, ClientId, ClientPlugin, Target, TargetId } from './index.js'; import type { HTTPSnippetOptions, Request } from '../index.js'; import { readdirSync, readFileSync, writeFileSync } from 'node:fs'; @@ -10,7 +10,7 @@ import short from '../fixtures/requests/short.cjs'; import { availableTargets, extname } from '../helpers/utils.js'; import { HTTPSnippet } from '../index.js'; -import { isClient, isTarget, addTarget, addTargetClient, targets } from './index.js'; +import { isClient, isTarget, addTarget, addTargetClient, targets, addClientPlugin } from './index.js'; const expectedBasePath = ['src', 'fixtures', 'requests']; @@ -318,3 +318,35 @@ describe('addTargetClient', () => { expect(result).toBe('This was generated from a custom client.'); }); }); + +describe('addClientPlugin', () => { + afterEach(() => { + delete targets.node.clientsById.custom; + }); + + it('should add a new custom target', async () => { + const customPlugin: ClientPlugin = { + target: 'node', + client: { + info: { + key: 'custom', + title: 'Custom HTTP library', + link: 'https://example.com', + description: 'A custom HTTP library', + extname: '.custom', + }, + convert: () => { + return 'This was generated from a custom client.'; + }, + }, + }; + + addClientPlugin(customPlugin); + + const snippet = new HTTPSnippet(short.log.entries[0].request as Request, {}); + + const result = await snippet.convert('node', 'custom'); + + expect(result).toBe('This was generated from a custom client.'); + }); +}); diff --git a/src/targets/index.ts b/src/targets/index.ts index 914a76802..dc35ec499 100644 --- a/src/targets/index.ts +++ b/src/targets/index.ts @@ -44,6 +44,11 @@ export interface Client = Record> { info: ClientInfo; } +export interface ClientPlugin { + client: Client; + target: TargetId; +} + export type Extension = `.${string}` | null; export interface TargetInfo { @@ -186,6 +191,10 @@ export const isClient = (client: Client): client is Client => { return true; }; +export const addClientPlugin = (plugin: ClientPlugin) => { + addTargetClient(plugin.target, plugin.client); +}; + export const addTargetClient = (targetId: TargetId, client: Client) => { if (!isClient(client)) { return;