-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add types declaration file for TS support * test: add TS tests * docs: add TS support documentation * Update package.json Co-authored-by: Manuel Spigolon <behemoth89@gmail.com> * handle additional options * chore: lint fix ts * chore: lint fix ts --------- Co-authored-by: Manuel Spigolon <behemoth89@gmail.com>
- Loading branch information
1 parent
15a74b5
commit a535a07
Showing
4 changed files
with
197 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { Readable } from "stream"; | ||
|
||
export type FormMethodOptions = { | ||
readonly payload?: string, | ||
readonly headers?: string | ||
} | ||
|
||
type FormMethodDefaultOptions = { | ||
readonly payload: 'payload', | ||
readonly headers: 'headers' | ||
} | ||
|
||
type Neverify<T> = { | ||
[K in keyof T]: never | ||
} | ||
|
||
type WithoutExtraProperties<BaseType, Arg extends BaseType> = Arg & Neverify<Omit<Arg, keyof BaseType>> | ||
|
||
type ComputedFormProperty<T extends FormMethodOptions, Property extends keyof T, DefaultValue extends string, ReturnType> = { | ||
[K in T[Property] as keyof T[Property] extends never | ||
? DefaultValue | ||
: K extends PropertyKey | ||
? K | ||
: never | ||
]: ReturnType | ||
} | ||
|
||
type FormMethodResult<T extends FormMethodOptions, K extends keyof T = keyof T> = string extends T[K] | ||
? ComputedFormProperty<T, 'headers', string, Record<string, string> | undefined> | ComputedFormProperty<T, 'payload', string, Readable | undefined> | ||
: ComputedFormProperty<T, 'headers', 'headers', Record<string, string>> & ComputedFormProperty<T, 'payload', 'payload', Readable> | ||
|
||
/** | ||
* @param {Record<string, unknown>} json - A JSON object that defines the fields of the form. | ||
* @param {FormMethodOptions} opts - An object containing properties to modify the output field names. | ||
* @returns {FormMethodResult} A JSON object with a payload field representing the data stream and a headers field containing the content-type set to "application/json". | ||
*/ | ||
export default function formMethod<T extends FormMethodOptions = FormMethodDefaultOptions>( | ||
json: Record<string, unknown>, | ||
opts?: T & WithoutExtraProperties<FormMethodOptions, T> | ||
): FormMethodResult<T> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import { expectAssignable } from 'tsd'; | ||
import formAutoContent, { FormMethodOptions } from "."; | ||
import { Readable } from "stream"; | ||
|
||
{ // no options supplied | ||
const myForm = formAutoContent({ | ||
field1: 'value1', | ||
field2: ['value2', 'value2.2'] | ||
}) | ||
|
||
expectAssignable<{ payload: Readable, headers: Record<string, string> }>(myForm) | ||
} | ||
|
||
{ // object options with type FormMethodOptions specified | ||
const option: FormMethodOptions = { payload: 'body', headers: 'head' } as const | ||
const myForm = formAutoContent({ | ||
field1: 'value1', | ||
field2: ['value2', 'value2.2'] | ||
}, option); | ||
|
||
expectAssignable<{ [x: string]: Record<string, string> | Readable | undefined }>(myForm) | ||
} | ||
|
||
{ // object options with satysfing FormMethodOptions | ||
const option = { payload: 'body', headers: 'head' } as const satisfies FormMethodOptions; | ||
|
||
const myForm = formAutoContent({ | ||
field1: 'value1', | ||
field2: ['value2', 'value2.2'] | ||
}, option); | ||
|
||
expectAssignable<{ body: Readable, head: Record<string, string> }>(myForm) | ||
} | ||
|
||
{ // object options as const | ||
const option = { payload: 'body', headers: 'head' } as const | ||
|
||
const myForm = formAutoContent({ | ||
field1: 'value1', | ||
field2: ['value2', 'value2.2'] | ||
}, option) | ||
|
||
expectAssignable<{ body: Readable, head: Record<string, string> }>(myForm) | ||
} | ||
|
||
{ // object options as const and only payload defined | ||
const option = { payload: 'body' } as const | ||
|
||
const myForm = formAutoContent({ | ||
field1: 'value1', | ||
field2: ['value2', 'value2.2'] | ||
}, option) | ||
|
||
expectAssignable<{ body: Readable, headers: Record<string, string> }>(myForm) | ||
} | ||
|
||
{ // object options as const and only headers defined | ||
const option = { headers: 'head' } as const | ||
|
||
const myForm = formAutoContent({ | ||
field1: 'value1', | ||
field2: ['value2', 'value2.2'] | ||
}, option) | ||
|
||
expectAssignable<{ payload: Readable, head: Record<string, string> }>(myForm) | ||
} | ||
|
||
{ // object options without as const | ||
const option = { payload: 'body', headers: 'head' } | ||
|
||
const myForm = formAutoContent({ | ||
field1: 'value1', | ||
field2: ['value2', 'value2.2'] | ||
}, option) | ||
|
||
expectAssignable<{ [x: string]: Readable | Record<string, string> | undefined }>(myForm) | ||
} | ||
|
||
{ // inline object | ||
const myForm = formAutoContent({ | ||
field1: 'value1', | ||
field2: ['value2', 'value2.2'] | ||
}, { payload: 'body', headers: 'head' } as const); | ||
|
||
expectAssignable<{ body: Readable, head: Record<string, string> }>(myForm) | ||
} | ||
|
||
{ // inline object with payload property | ||
const myForm = formAutoContent({ | ||
field1: 'value1', | ||
field2: ['value2', 'value2.2'] | ||
}, { payload: 'body' } as const); | ||
|
||
expectAssignable<{ body: Readable, headers: Record<string, string> }>(myForm) | ||
} | ||
|
||
{ // inline object with headers property | ||
const myForm = formAutoContent({ | ||
field1: 'value1', | ||
field2: ['value2', 'value2.2'] | ||
}, { headers: 'head' } as const); | ||
|
||
expectAssignable<{ payload: Readable, head: Record<string, string> }>(myForm) | ||
} | ||
|
||
{ // additional properties are not allowed | ||
formAutoContent({ | ||
field1: 'value1', | ||
field2: ['value2', 'value2.2'] | ||
// @ts-expect-error | ||
}, { headers: 'head', foo: '' } as const); | ||
|
||
formAutoContent({ | ||
field1: 'value1', | ||
field2: ['value2', 'value2.2'] | ||
// @ts-expect-error | ||
}, { payload: 'body', foo: '' } as const); | ||
|
||
formAutoContent({ | ||
field1: 'value1', | ||
field2: ['value2', 'value2.2'] | ||
// @ts-expect-error | ||
}, { foo: '' } as const); | ||
} |