From 65abf280a89988f6a5985c06a1214116b345e22b Mon Sep 17 00:00:00 2001 From: yumauri Date: Sun, 7 Feb 2021 20:38:49 +0300 Subject: [PATCH] Introduce `adjust` function (issue #26) --- README.md | 25 +++++++++++++++++++ package.json | 2 +- src/adjust.ts | 29 ++++++++++++++++++++++ src/index.ts | 1 + test/adjust.spec.ts | 59 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/adjust.ts create mode 100644 test/adjust.spec.ts diff --git a/README.md b/README.md index d6c6211..330be30 100644 --- a/README.md +++ b/README.md @@ -330,6 +330,31 @@ const toMergedPDF = pipe( ) ``` +## Advanced fine adjustment + +There is special function `adjust`, which you can use to modify _any_ field in prepared internal `Request` object. You can check internal `Request` object structure in types. Any object, passed to `adjust`, will be merged with prepared `Request`. + +For example, you can modify `url`, if your Gotenberg instance is working behind reverse proxy with some weird url replacement rules: + +```typescript +import { pipe, gotenberg, convert, html, adjust, please } from 'gotenberg-js-client' + +// Original Gotenberg HTML conversion endpoint is +// -> /convert/html +// But your reverse proxy uses location +// -> /hidden/html/conversion +const toPDF = pipe( + gotenberg('http://localhost:3000'), + convert, + html, + adjust({ url: '/hidden/html/conversion' }), + please +) +``` + +But, using that function, remember about Peter Parker principle: +> "With great power comes great responsibility" + ## Bonus If you happen to use this package from JavaScript, you will, obviously, lost type safety, but in return, you can use [proposed pipe operator](https://github.com/tc39/proposal-pipeline-operator) (with [Babel plugin](https://babeljs.io/docs/en/babel-plugin-proposal-pipeline-operator)), to get beauty like this: diff --git a/package.json b/package.json index 3814d4e..2c3709c 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ { "path": "pkg/dist-node/index.js", "webpack": false, - "limit": "4119 B" + "limit": "4216 B" } ], "@pika/pack": { diff --git a/src/adjust.ts b/src/adjust.ts new file mode 100644 index 0000000..ab0d6f1 --- /dev/null +++ b/src/adjust.ts @@ -0,0 +1,29 @@ +import { Request } from './_types' + +/** + * Recursively merge requests + */ +const merge = (request: RequestEx, modify: Partial) => { + const result = { ...request, ...modify } + + for (const key in modify) { + if ( + modify[key] && + request[key] && + typeof modify[key] === 'object' && + typeof request[key] === 'object' + ) { + result[key] = merge(request[key], modify[key]) + } + } + + return result +} + +/** + * Adjust any Request *object* fields, for any request + * @return new typed Request, doesn't modify original Request + */ +export const adjust: { + (modify: Partial): (request: RequestEx) => RequestEx +} = (modify) => (request) => merge(request, modify) diff --git a/src/index.ts b/src/index.ts index 2e79272..a803acf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,6 +12,7 @@ export { html } from './html' export { url } from './url' // export modifiers functions and constants +export { adjust } from './adjust' export { add } from './add' export { set } from './set' export { to } from './to' diff --git a/test/adjust.spec.ts b/test/adjust.spec.ts new file mode 100644 index 0000000..4d21e58 --- /dev/null +++ b/test/adjust.spec.ts @@ -0,0 +1,59 @@ +import { adjust, Request, RequestType } from '../src' + +// dumb object to test purity +const dumb: Request = { + type: RequestType.Undefined, + url: 'test', + fields: { + scale: 1, + landscape: true, + pageRanges: '1-2', + }, + client: { + post: () => { + throw new Error('not implemented') + }, + }, +} + +test('Should adjust flat fields', () => { + expect(adjust({})(dumb)).toEqual({ ...dumb }) + expect(adjust({ url: 'changed' })(dumb)).toEqual({ ...dumb, url: 'changed' }) +}) + +test('Should adjust deep fields', () => { + expect(adjust({ fields: { landscape: false } })(dumb)).toEqual({ + ...dumb, + fields: { + ...dumb.fields, + landscape: false, + }, + }) + expect(adjust({ headers: { Authorization: 'Bearer token' } })(dumb)).toEqual({ + ...dumb, + headers: { + Authorization: 'Bearer token', + }, + }) + expect( + adjust({ headers: { Authorization: 'Bearer token' } })({ + ...dumb, + headers: { 'X-Header': 'test' }, + }) + ).toEqual({ + ...dumb, + headers: { + Authorization: 'Bearer token', + 'X-Header': 'test', + }, + }) +}) + +test('Should replace deep fields', () => { + expect( + adjust({ headers: { Authorization: 'Bearer token' } })({ + ...dumb, + headers: { Authorization: 'Basic dXNlcjpwYXNzd29yZA==' }, + }) + ).toEqual({ ...dumb, headers: { Authorization: 'Bearer token' } }) +})