Skip to content

Commit

Permalink
Encoding added + new Cookie helper.
Browse files Browse the repository at this point in the history
  • Loading branch information
houd1ni committed Dec 2, 2019
1 parent d67da85 commit 42f6229
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 12 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const api = new Fetch({
},
// fetch adapter. Defaults to the window fetch.
// In node can work with https://www.npmjs.com/package/node-fetch
// But there many of config fields are not implemented, i.e. credentials.
adapter?: fetch,
credentials?: 'omit' | 'same-origin' | 'include', // fetch API credentials field.
throwCodes?: /5../, // HTTP status codes to throw. Defaults to /\n/ (no throws at all).
Expand Down
17 changes: 17 additions & 0 deletions dist/bundle.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface Headers {
}
export declare type Method = 'get' | 'post' | 'put' | 'head' | 'delete' | 'options' | 'trace' | 'connect';
export declare type HandleArrays = '[]' | ',';
export declare type Encoding = 'json' | 'url' | 'multipart';
export declare type OutMiddleware = (query: Query) => Promise<Query>;
export declare type InMiddleware = ({ query: Query, response: any }: {
query: any;
Expand All @@ -27,6 +28,7 @@ export interface Config {
credentials: Credentials;
throwCodes: RegExp;
handleArrays: HandleArrays;
encoding: Encoding;
adapter: (url: string, conf: AnyObject) => Promise<AnyObject> | null;
middleware: {
in?: InMiddleware[];
Expand All @@ -44,6 +46,7 @@ export interface Query {
};
/** Request body. For POST requests in particular. */
body: any;
encoding: Encoding;
headers: Headers;
credentials: Credentials;
throwCodes?: RegExp;
Expand Down Expand Up @@ -71,6 +74,20 @@ export declare const mapKeys: Curry.Curry<(keyMap: {
[oldKey: string]: string;
}, o: AnyObject) => any>;
export declare const asyncpipe: (...fns: AnyFunc[]) => (data?: any) => Promise<any>;
export interface CookieData {
name: string;
value: any;
attrs: AnyObject;
}
export declare class Cookie {
data: Partial<CookieData>;
parse(str: string): Partial<CookieData>;
get(): Partial<CookieData>;
set(v: any): void;
stringify(): any;
toString(): any;
constructor(str?: string);
}
export declare class Fetch {
private config;
private middleware;
Expand Down
2 changes: 1 addition & 1 deletion dist/bundle.esm.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"prod:es": "cross-env NODE_ENV=production BUILD=es rollup -c",
"prod": "npm run gentypes && npm run prod:es && npm run prod:cjs"
},
"version": "0.2.7",
"version": "0.3.0",
"ava": {
"files": [
"./test/specs/*.ts"
Expand Down
27 changes: 22 additions & 5 deletions src/Fetch.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type, mergeDeepRight } from 'ramda'
import { type, mergeDeepRight, compose, assoc } from 'ramda'
import { formURI, addBase, hole } from './utils'
import { Query, Config, OutMiddleware, InMiddleware, FetchData } from './types'
import { Query, Config, OutMiddleware, InMiddleware, FetchData, AnyFunc } from './types'
import { addHeaders, asyncpipe } from './helpers'

const default_config: Config = {
Expand All @@ -12,6 +12,7 @@ const default_config: Config = {
throwCodes: /\n/, // doesn't throw.
credentials: 'same-origin',
handleArrays: '[]',
encoding: 'json',
middleware: {
in: [],
out: []
Expand Down Expand Up @@ -40,10 +41,25 @@ export class Fetch {
},
async (query: Query) => {
if(type(query.body) == 'Object') {
query = addHeaders({'Content-Type': 'application/json'}, query)
query.body = JSON.stringify(query.body)
const ct = 'Content-Type'
switch(query.encoding) {
case 'json':
return (compose as any)(
addHeaders({[ct]: 'application/json'}),
assoc('body', JSON.stringify(query.body))
)(query)
case 'url':
return (compose as any)(
addHeaders({[ct]: 'application/x-www-form-urlencoded'}),
assoc('body', formURI({ params: query.body }).slice(1))
)(query)
case 'multipart':
console.warn('lafetch: multipart encoding is not implemented yet.')
default:
// TODO:
return query
}
}
return query
},
async (query: Query) => {
for(const name in query.headers) {
Expand Down Expand Up @@ -114,6 +130,7 @@ export class Fetch {
credentials: this.config.credentials,
throwCodes: this.config.throwCodes,
handleArrays: this.config.handleArrays,
encoding: this.config.encoding,
misc: {}
}
const middle = {} as { in: InMiddleware, out: OutMiddleware }
Expand Down
38 changes: 36 additions & 2 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import {
tap, bind as rbind
} from 'ramda'
import { Query, Headers, AnyObject, AnyFunc } from './types'
import { parseCookie, stringifyCookie } from './utils'

/** Adds new headers to provided Query. */
export const addHeaders = curry((headers: Headers, query: Query): Query => {
return {
...query,
headers: Object.assign({}, query.headers, headers)
headers: { ...query.headers, ...headers }
}
})

Expand Down Expand Up @@ -58,4 +59,37 @@ export const asyncpipe = (() => {
const pipe = async (fns: AnyFunc[], data: any, i: number): Promise<any> =>
~i ? await pipe(fns, await fns[i](data), --i) : data
return (...fns: AnyFunc[]) => (data?: any) => pipe(fns, data, fns.length-1)
})()
})()

interface CookieData {
name: string,
value: any,
attrs: AnyObject
}

export class Cookie {
public data: Partial<CookieData> = null
public parse(str: string) {
this.data = parseCookie(str)
return this.get()
}
public get() {
return this.data
}
public set(v: any) {
this.data.value = v
}
public stringify() {
return stringifyCookie(this.data)
}
public toString() {
return this.stringify()
}
constructor(str?: string) {
if(str) {
this.parse(str)
} else {
this.data = { name: '', value: null, attrs: {} }
}
}
}
3 changes: 3 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface Headers {

export type Method = 'get' | 'post' | 'put' | 'head' | 'delete' | 'options' | 'trace' | 'connect'
export type HandleArrays = '[]' | ','
export type Encoding = 'json' | 'url' | 'multipart'

export type OutMiddleware = (query: Query) => Promise<Query>
export type InMiddleware = ({ query: Query, response: any }) =>
Expand All @@ -25,6 +26,7 @@ export interface Config {
credentials: Credentials
throwCodes: RegExp
handleArrays: HandleArrays
encoding: Encoding
adapter: (url: string, conf: AnyObject) => Promise<AnyObject> | null
middleware: {
in?: InMiddleware[]
Expand All @@ -43,6 +45,7 @@ export interface Query {
}
/** Request body. For POST requests in particular. */
body: any
encoding: Encoding
headers: Headers
credentials: Credentials
throwCodes?: RegExp
Expand Down
36 changes: 34 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@

import { curry, type, join, replace, reduce, compose, append } from 'ramda'
import { Query, HandleArrays, AnyObject } from './types'
import {
curry, type, join, replace, reduce, compose,
append, fromPairs, map, split, equals, not, filter
} from 'ramda'
import { Query, HandleArrays, AnyObject, AnyFunc } from './types'
import toPairs from 'ramda/es/toPairs'
import complement from 'ramda/es/complement'

export const trim = curry((symbols: string, str: string) => {
let found_first = null,
Expand Down Expand Up @@ -58,6 +63,33 @@ const stringifyPair = (
}
}

export const splitOnce = curry((delimiter: RegExp, s: string) => {
const i = s.search(delimiter)
return ~i ? [ s.slice(0, i), s.slice(i+1) ] : [ s ]
})

export const parseCookie = compose(
([[k, v], ...attrs]) => ({
name: k,
value: v,
attrs: (equals(attrs, [null]) ? {} : fromPairs(attrs))
}),
map(compose(
([key, value]) => key
? [key, value ? decodeURIComponent(value) : true]
: null,
splitOnce(/=/)
)),
split(/; ?/g)
)

export const stringifyCookie = (compose as any)(
join('; '),
filter(compose(not, equals('Null'), type)),
map((([k, v]) => v === null ? null : (v===true ? k : `${k}=${v}`))),
({ name, value, attrs }) => [ [name, value], ...toPairs(attrs) ]
)

/** Turns query params into query string. */
export const formURI = (query: Partial<Query>) => {
const parts: string[] = []
Expand Down

0 comments on commit 42f6229

Please sign in to comment.