Skip to content

Commit

Permalink
feat(core): Add rxjs-axios core (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoseLion authored Nov 7, 2022
1 parent 4f459b4 commit 99a239d
Show file tree
Hide file tree
Showing 13 changed files with 2,350 additions and 0 deletions.
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
### Dependencies ###
node_modules/
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

### Auto-generated ###
build/
dist/
dist.tar.gz

### Logs ###
*.log
9 changes: 9 additions & 0 deletions .yarn/plugins/@yarnpkg/plugin-engines.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* eslint-disable */
//prettier-ignore
module.exports = {
name: "@yarnpkg/plugin-engines",
factory: function (require) {
var plugin=(()=>{var P=Object.create,m=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var b=Object.getPrototypeOf,Y=Object.prototype.hasOwnProperty;var T=n=>m(n,"__esModule",{value:!0});var i=n=>{if(typeof require!="undefined")return require(n);throw new Error('Dynamic require of "'+n+'" is not supported')};var V=(n,e)=>{for(var r in e)m(n,r,{get:e[r],enumerable:!0})},N=(n,e,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of j(e))!Y.call(n,t)&&t!=="default"&&m(n,t,{get:()=>e[t],enumerable:!(r=R(e,t))||r.enumerable});return n},s=n=>N(T(m(n!=null?P(b(n)):{},"default",n&&n.__esModule&&"default"in n?{get:()=>n.default,enumerable:!0}:{value:n,enumerable:!0})),n);var S={};V(S,{default:()=>$});var o=s(i("@yarnpkg/core")),c;(function(r){r.Yarn="Yarn",r.Console="Console"})(c||(c={}));var h=class{constructor(e){this.throwWrongEngineError=(e,r)=>{let t=this.formatErrorMessage(e,r);this.throwError(t)};this.throwError=e=>{switch(this.errorReporter){case c.Yarn:this.reportYarnError(e);break;case c.Console:default:this.reportConsoleError(e);break}};this.reportYarnError=e=>{throw new o.ReportError(o.MessageName.UNNAMED,e)};this.reportConsoleError=e=>{console.error(e),process.exit(1)};this.formatErrorMessage=(e,r)=>{let{configuration:t}=this.project,p=o.formatUtils.applyStyle(t,o.formatUtils.pretty(t,this.engine,"green"),2),g=o.formatUtils.pretty(t,e,"cyan"),d=o.formatUtils.pretty(t,r,"cyan"),w=`The current ${p} version ${g} does not satisfy the required version ${d}.`;return o.formatUtils.pretty(t,w,"red")};this.project=e.project,this.errorReporter=e.errorReporter}};var f=s(i("fs")),u=s(i("path")),l=s(i("semver")),k=s(i("@yarnpkg/fslib")),a=s(i("@yarnpkg/core"));var v=class extends h{constructor(){super(...arguments);this.resolveNvmRequiredVersion=()=>{let{configuration:e,cwd:r}=this.project,t=(0,u.resolve)(k.npath.fromPortablePath(r),".nvmrc"),p=a.formatUtils.applyStyle(e,a.formatUtils.pretty(e,this.engine,"green"),2);if(!(0,f.existsSync)(t)){this.throwError(a.formatUtils.pretty(e,`Unable to verify the ${p} version. The .nvmrc file does not exist.`,"red"));return}let g=(0,f.readFileSync)(t,"utf-8").trim();if((0,l.validRange)(g))return g;let d=a.formatUtils.pretty(e,".nvmrc","yellow");this.throwError(a.formatUtils.pretty(e,`Unable to verify the ${p} version. The ${d} file contains an invalid semver range.`,"red"))}}get engine(){return"Node"}verifyEngine(e){let r=e.node;r!=null&&(r===".nvmrc"&&(r=this.resolveNvmRequiredVersion()),(0,l.satisfies)(process.version,r,{includePrerelease:!0})||this.throwWrongEngineError(process.version.replace(/^v/i,""),r.replace(/^v/i,"")))}};var x=s(i("semver")),y=s(i("@yarnpkg/core"));var E=class extends h{get engine(){return"Yarn"}verifyEngine(e){let r=e.yarn;r!=null&&((0,x.satisfies)(y.YarnVersion,r,{includePrerelease:!0})||this.throwWrongEngineError(y.YarnVersion,r))}};var C=n=>e=>{let{engines:r={}}=e.getWorkspaceByCwd(e.cwd).manifest.raw,t={project:e,errorReporter:n};[new v(t),new E(t)].forEach(g=>g.verifyEngine(r))},q={hooks:{validateProject:C(c.Yarn),setupScriptEnvironment:C(c.Console)}},$=q;return S;})();
return plugin;
}
};
541 changes: 541 additions & 0 deletions .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs

Large diffs are not rendered by default.

801 changes: 801 additions & 0 deletions .yarn/releases/yarn-3.2.4.cjs

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
nodeLinker: node-modules

plugins:
- path: .yarn/plugins/@yarnpkg/plugin-engines.cjs
spec: "https://raw.githubusercontent.com/devoto13/yarn-plugin-engines/main/bundles/%40yarnpkg/plugin-engines.js"
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"

yarnPath: .yarn/releases/yarn-3.2.4.cjs
41 changes: 41 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "rxjs-axios",
"version": "0.0.0",
"description": "A complete Axios wrapper that uses RxJS observables",
"author": "Jose Luis Leon <[email protected]>",
"private": true,
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist/"
],
"engines": {
"node": ">=16"
},
"scripts": {
"build": "tsc -p tsconfig.prod.json",
"compile": "tsc",
"lint": "tslint -p tsconfig.json -c tslint.json \"**/*.ts\""
},
"devDependencies": {
"@types/node": "^18.11.9",
"axios": "^1.1.3",
"rxjs": "^7.5.7",
"tslint": "^6.1.3",
"typescript": "^4.8.4"
},
"peerDependencies": {
"axios": "~1.1.3",
"rxjs": "~7.5.7"
},
"peerDependenciesMeta": {
"axios": {
"optional": false
},
"rxjs": {
"optional": false
}
},
"packageManager": "[email protected]"
}
51 changes: 51 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import defaultAxios, { AxiosResponse } from "axios";
import { Observable } from "rxjs";

import { RxjsAxios } from "./lib/RxjsAxios";

export type AxiosObservable<T> = Observable<AxiosResponse<T>>;

/**
* Re-export all everithing from axios, except anything to do with promises.
*/
export {
AxiosError,
CanceledError,
type AxiosAdapter,
type AxiosBasicCredentials,
type AxiosDefaults,
type AxiosHeaders,
type AxiosInterceptorManager,
type AxiosInterceptorOptions,
type AxiosProgressEvent,
type AxiosProxyConfig,
type AxiosRequestConfig,
type AxiosRequestHeaders,
type AxiosRequestTransformer,
type AxiosResponse,
type AxiosResponseHeaders,
type AxiosResponseTransformer,
type CreateAxiosDefaults,
type CustomParamsSerializer,
type FormDataVisitorHelpers,
type FormSerializerOptions,
type GenericAbortSignal,
type GenericFormData,
type GenericHTMLFormElement,
type HeadersDefaults,
type HttpStatusCode,
type Method,
type ParamEncoder,
type ParamsSerializerOptions,
type RawAxiosRequestHeaders,
type RawAxiosResponseHeaders,
type ResponseType,
type SerializerOptions,
type SerializerVisitor,
type TransitionalOptions,
type responseEncoding,
} from "axios";
export { RxjsAxios as Axios } from "./lib/RxjsAxios";

export const axios = RxjsAxios.of(defaultAxios);
export default axios;
225 changes: 225 additions & 0 deletions src/lib/RxjsAxios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
import axios, {
AxiosDefaults,
AxiosError,
AxiosInstance,
AxiosInterceptorManager,
AxiosRequestConfig,
AxiosResponse, Cancel,
CancelToken,
CancelTokenSource,
CancelTokenStatic,
CreateAxiosDefaults,
FormSerializerOptions,
GenericFormData,
GenericHTMLFormElement,
} from "axios";
import { Observable } from "rxjs";

import { observify } from "./observify";

interface Interceptors {
request: AxiosInterceptorManager<AxiosRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse>;
}

interface Cancellable {
cancelSource: CancelTokenSource;
cancelToken: CancelToken;
}

export class RxjsAxios {

private axios: AxiosInstance;

private CancelToken: CancelTokenStatic;

private constructor(instance: AxiosInstance) {
this.axios = instance;
this.CancelToken = axios.CancelToken;
}

public static of(instance: AxiosInstance): RxjsAxios {
return new RxjsAxios(instance);
}

public static create<D>(config?: CreateAxiosDefaults<D>): RxjsAxios {
const instance = axios.create(config);

return new RxjsAxios(instance);
}

public static isAxiosError<T, D>(error: unknown): error is AxiosError<T, D> {
return axios.isAxiosError<T, D>(error);
}

public static isCancel(error: unknown): error is Cancel {
return axios.isCancel(error);
}

public static toFormData(
sourceObj: object,
targetFormData?: GenericFormData,
options?: FormSerializerOptions,
): GenericFormData {
return axios.toFormData(sourceObj, targetFormData, options);
}

public static formToJSON(form: GenericFormData | GenericHTMLFormElement): object {
return axios.formToJSON(form);
}

public get defaults(): AxiosDefaults {
return this.axios.defaults;
}

public get interceptors(): Interceptors {
return this.axios.interceptors;
}

public request<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
config: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.request<T, R, D>({ ...config, cancelToken }),
cancelSource,
);
}

public get<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.get<T, R, D>(url, { ...config, cancelToken }),
cancelSource,
);
}

public delete<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.delete<T, R, D>(url, { ...config, cancelToken }),
cancelSource,
);
}

public head<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.head<T, R, D>(url, { ...config, cancelToken }),
cancelSource,
);
}

public options<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.options<T, R, D>(url, { ...config, cancelToken }),
cancelSource,
);
}

public post<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.post<T, R, D>(url, data, { ...config, cancelToken }),
cancelSource,
);
}

public put<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.put<T, R, D>(url, data, { ...config, cancelToken }),
cancelSource,
);
}

public patch<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.patch<T, R, D>(url, data, { ...config, cancelToken }),
cancelSource,
);
}

public postForm<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.postForm<T, R, D>(url, data, { ...config, cancelToken }),
cancelSource,
);
}

public putForm<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.putForm<T, R, D>(url, data, { ...config, cancelToken }),
cancelSource,
);
}

public patchForm<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.patchForm<T, R, D>(url, data, { ...config, cancelToken }),
cancelSource,
);
}

private makeCancellable(): Cancellable {
const cancelSource = this.CancelToken.source();
const cancelToken = cancelSource.token;

return {
cancelSource,
cancelToken,
};
}
}
16 changes: 16 additions & 0 deletions src/lib/observify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { AxiosResponse, CancelTokenSource } from "axios";
import { Observable } from "rxjs";

export function observify<T, R extends AxiosResponse<T>>(
makeRequest: () => Promise<R>,
cancelSource: CancelTokenSource,
): Observable<R> {
return new Observable(subscriber => {
makeRequest()
.then(response => subscriber.next(response))
.catch(error => subscriber.error(error))
.finally(() => subscriber.complete());

return { unsubscribe: () => cancelSource.cancel() };
});
}
Loading

0 comments on commit 99a239d

Please sign in to comment.