@lxlib/mock
Version:
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 9.1.1.
627 lines (617 loc) • 18.2 kB
JavaScript
import { Injectable, Injector, NgModule } from '@angular/core';
import { HttpErrorResponse, HttpResponseBase, HttpResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
import { throwError, of } from 'rxjs';
import { delay } from 'rxjs/operators';
/**
* @fileoverview added by tsickle
* Generated from: src/interface.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @record
*/
function MockCachedRule() { }
if (false) {
/** @type {?} */
MockCachedRule.prototype.method;
/** @type {?} */
MockCachedRule.prototype.url;
/** @type {?} */
MockCachedRule.prototype.martcher;
/** @type {?} */
MockCachedRule.prototype.segments;
/* Skipping unhandled member: [key: string]: any;*/
/**
* @param {?} req
* @return {?}
*/
MockCachedRule.prototype.callback = function (req) { };
}
/**
* @record
*/
function MockRule() { }
if (false) {
/** @type {?} */
MockRule.prototype.method;
/** @type {?} */
MockRule.prototype.url;
/**
* 路由参数
* @type {?|undefined}
*/
MockRule.prototype.params;
/* Skipping unhandled member: [key: string]: any;*/
/**
* @param {?} req
* @return {?}
*/
MockRule.prototype.callback = function (req) { };
}
/**
* @record
*/
function MockRequest() { }
if (false) {
/**
* 路由参数
* @type {?|undefined}
*/
MockRequest.prototype.params;
/**
* URL参数
* @type {?|undefined}
*/
MockRequest.prototype.queryString;
/** @type {?|undefined} */
MockRequest.prototype.headers;
/** @type {?|undefined} */
MockRequest.prototype.body;
/**
* 原始 `HttpRequest`
* @type {?}
*/
MockRequest.prototype.original;
}
/**
* @fileoverview added by tsickle
* Generated from: src/status.error.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class MockStatusError {
/**
* @param {?} status
* @param {?=} error
*/
constructor(status, error) {
this.status = status;
this.error = error;
}
}
if (false) {
/** @type {?} */
MockStatusError.prototype.statusText;
/** @type {?} */
MockStatusError.prototype.status;
/** @type {?} */
MockStatusError.prototype.error;
}
/**
* @fileoverview added by tsickle
* Generated from: src/mock.config.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class LxlibMockConfig {
constructor() {
/**
* 请求延迟,单位:毫秒,默认:`300`
*/
this.delay = 300;
/**
* 是否强制所有请求都Mock,`true` 表示当请求的URL不存在时直接返回 404 错误,`false` 表示未命中时发送真实HTTP请求
*/
this.force = false;
/**
* 是否打印 Mock 请求信息,弥补浏览器无Network信息
*/
this.log = true;
/**
* 是否拦截命中后继续调用后续拦截器的 `intercept` 方法,默认:`true`
*/
this.executeOtherInterceptors = true;
}
}
if (false) {
/**
* 规则定义数据
* @type {?}
*/
LxlibMockConfig.prototype.data;
/**
* 请求延迟,单位:毫秒,默认:`300`
* @type {?}
*/
LxlibMockConfig.prototype.delay;
/**
* 是否强制所有请求都Mock,`true` 表示当请求的URL不存在时直接返回 404 错误,`false` 表示未命中时发送真实HTTP请求
* @type {?}
*/
LxlibMockConfig.prototype.force;
/**
* 是否打印 Mock 请求信息,弥补浏览器无Network信息
* @type {?}
*/
LxlibMockConfig.prototype.log;
/**
* 是否拦截命中后继续调用后续拦截器的 `intercept` 方法,默认:`true`
* @type {?}
*/
LxlibMockConfig.prototype.executeOtherInterceptors;
}
/**
* @fileoverview added by tsickle
* Generated from: src/mock.service.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class MockService {
/**
* @param {?} config
*/
constructor(config) {
this.config = config;
this.cached = [];
this.applyMock();
delete this.config.data;
}
// #region parse rule
/**
* @private
* @return {?}
*/
applyMock() {
this.cached = [];
try {
this.realApplyMock();
}
catch (e) {
this.outputError(e);
}
}
/**
* @private
* @return {?}
*/
realApplyMock() {
/** @type {?} */
const data = this.config.data;
if (!data)
return;
Object.keys(data).forEach((/**
* @param {?} key
* @return {?}
*/
(key) => {
/** @type {?} */
const rules = data[key];
if (!rules)
return;
Object.keys(rules).forEach((/**
* @param {?} ruleKey
* @return {?}
*/
(ruleKey) => {
/** @type {?} */
const value = rules[ruleKey];
if (!(typeof value === 'function' || typeof value === 'object' || typeof value === 'string')) {
throw Error(`mock value of [${key}-${ruleKey}] should be function or object or string, but got ${typeof value}`);
}
/** @type {?} */
const rule = this.genRule(ruleKey, value);
if (['GET', 'POST', 'PUT', 'HEAD', 'DELETE', 'PATCH', 'OPTIONS'].indexOf(rule.method) === -1) {
throw Error(`method of ${key}-${ruleKey} is not valid`);
}
/** @type {?} */
const item = this.cached.find((/**
* @param {?} w
* @return {?}
*/
w => w.url === rule.url && w.method === rule.method));
if (item) {
item.callback = rule.callback;
}
else {
this.cached.push(rule);
}
}));
}));
// regular ordering
this.cached.sort((/**
* @param {?} a
* @param {?} b
* @return {?}
*/
(a, b) => (b.martcher || '').toString().length - (a.martcher || '').toString().length));
}
/**
* @private
* @param {?} key
* @param {?} callback
* @return {?}
*/
genRule(key, callback) {
/** @type {?} */
let method = 'GET';
/** @type {?} */
let url = key;
if (key.indexOf(' ') > -1) {
/** @type {?} */
const splited = key.split(' ');
method = splited[0].toLowerCase();
url = splited[1];
}
/** @type {?} */
let martcher = null;
/** @type {?} */
let segments = [];
if (~url.indexOf(':')) {
segments = (/** @type {?} */ (url)).split('/')
.filter((/**
* @param {?} segment
* @return {?}
*/
segment => segment.startsWith(':')))
.map((/**
* @param {?} v
* @return {?}
*/
v => v.substring(1)));
/** @type {?} */
const reStr = (/** @type {?} */ (url)).split('/')
.map((/**
* @param {?} segment
* @return {?}
*/
segment => (segment.startsWith(':') ? `([^/]+)` : segment)))
.join('/');
martcher = new RegExp(`^${reStr}`, 'i');
}
else if (/(\([^)]+\))/i.test(url)) {
martcher = new RegExp(url, 'i');
}
return {
url,
martcher,
segments,
callback,
method: method.toUpperCase(),
};
}
/**
* @private
* @param {?} error
* @return {?}
*/
outputError(error) {
/** @type {?} */
const filePath = error.message.split(': ')[0];
/** @type {?} */
const errors = ((/** @type {?} */ (error.stack)))
.split('\n')
.filter((/**
* @param {?} line
* @return {?}
*/
line => line.trim().indexOf('at ') !== 0))
.map((/**
* @param {?} line
* @return {?}
*/
line => line.replace(`${filePath}: `, '')));
errors.splice(1, 0, '');
console.group();
console.warn(`==========Failed to parse mock config.==========`);
console.log(errors.join('\n'));
console.groupEnd();
throw error;
}
// #endregion
/**
* @param {?} method
* @param {?} url
* @return {?}
*/
getRule(method, url) {
method = (method || 'GET').toUpperCase();
/** @type {?} */
const params = {};
/** @type {?} */
const list = this.cached.filter((/**
* @param {?} w
* @return {?}
*/
w => w.method === method && (w.martcher ? w.martcher.test(url) : w.url === url)));
if (list.length === 0)
return null;
/** @type {?} */
const ret = list.find((/**
* @param {?} w
* @return {?}
*/
w => w.url === url)) || list[0];
if (ret.martcher) {
/** @type {?} */
const execArr = ret.martcher.exec(url);
(/** @type {?} */ (execArr)).slice(1).map((/**
* @param {?} value
* @param {?} index
* @return {?}
*/
(value, index) => {
params[ret.segments[index]] = value;
}));
}
return {
url,
method: ret.method,
params,
callback: ret.callback,
};
}
/**
* @return {?}
*/
clearCache() {
this.cached = [];
}
/**
* @return {?}
*/
get rules() {
return this.cached;
}
/**
* @return {?}
*/
ngOnDestroy() {
this.clearCache();
}
}
MockService.decorators = [
{ type: Injectable }
];
/** @nocollapse */
MockService.ctorParameters = () => [
{ type: LxlibMockConfig }
];
if (false) {
/**
* @type {?}
* @private
*/
MockService.prototype.cached;
/**
* @type {?}
* @private
*/
MockService.prototype.config;
}
/**
* @fileoverview added by tsickle
* Generated from: src/mock.interceptor.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class HttpMockInterceptorHandler {
/**
* @param {?} next
* @param {?} interceptor
*/
constructor(next, interceptor) {
this.next = next;
this.interceptor = interceptor;
}
/**
* @param {?} req
* @return {?}
*/
handle(req) {
return this.interceptor.intercept(req, this.next);
}
}
if (false) {
/**
* @type {?}
* @private
*/
HttpMockInterceptorHandler.prototype.next;
/**
* @type {?}
* @private
*/
HttpMockInterceptorHandler.prototype.interceptor;
}
class MockInterceptor {
/**
* @param {?} injector
*/
constructor(injector) {
this.injector = injector;
}
/**
* @param {?} req
* @param {?} next
* @return {?}
*/
intercept(req, next) {
/** @type {?} */
const src = this.injector.get(MockService);
/** @type {?} */
const config = Object.assign({ delay: 300, force: false, log: true, executeOtherInterceptors: true }, this.injector.get(LxlibMockConfig));
/** @type {?} */
const rule = src.getRule(req.method, req.url.split('?')[0]);
if (!rule && !config.force) {
return next.handle(req);
}
/** @type {?} */
let res;
switch (typeof (/** @type {?} */ (rule)).callback) {
case 'function':
/** @type {?} */
const mockRequest = {
original: req,
body: req.body,
queryString: {},
headers: {},
params: (/** @type {?} */ (rule)).params,
};
/** @type {?} */
const urlParams = req.url.split('?');
if (urlParams.length > 1) {
urlParams[1].split('&').forEach((/**
* @param {?} item
* @return {?}
*/
item => {
/** @type {?} */
const itemArr = item.split('=');
/** @type {?} */
const key = itemArr[0];
/** @type {?} */
const value = itemArr[1];
// is array
if (Object.keys(mockRequest.queryString).includes(key)) {
if (!Array.isArray(mockRequest.queryString[key])) {
mockRequest.queryString[key] = [mockRequest.queryString[key]];
}
mockRequest.queryString[key].push(value);
}
else {
mockRequest.queryString[key] = value;
}
}));
}
req.params.keys().forEach((/**
* @param {?} key
* @return {?}
*/
key => (mockRequest.queryString[key] = req.params.get(key))));
req.headers.keys().forEach((/**
* @param {?} key
* @return {?}
*/
key => (mockRequest.headers[key] = req.headers.get(key))));
try {
res = (/** @type {?} */ (rule)).callback.call(this, mockRequest);
}
catch (e) {
res = new HttpErrorResponse({
url: req.url,
headers: req.headers,
status: 400,
statusText: e.statusText || 'Unknown Error',
error: e.error,
});
if (e instanceof MockStatusError) {
res.status = e.status;
}
}
break;
default:
res = (/** @type {?} */ (rule)).callback;
break;
}
if (!(res instanceof HttpResponseBase)) {
res = new HttpResponse({
status: 200,
url: req.url,
body: res,
});
}
if (config.log) {
console.log(`%c👽${req.method}->${req.url}->request`, 'background:#000;color:#bada55', req);
console.log(`%c👽${req.method}->${req.url}->response`, 'background:#000;color:#bada55', res);
}
/** @type {?} */
const res$ = res instanceof HttpErrorResponse ? throwError(res) : of(res);
if (config.executeOtherInterceptors) {
/** @type {?} */
const interceptors = this.injector.get(HTTP_INTERCEPTORS, []);
/** @type {?} */
const lastInterceptors = interceptors.slice(interceptors.indexOf(this) + 1);
if (lastInterceptors.length > 0) {
/** @type {?} */
const chain = lastInterceptors.reduceRight((/**
* @param {?} _next
* @param {?} _interceptor
* @return {?}
*/
(_next, _interceptor) => new HttpMockInterceptorHandler(_next, _interceptor)), (/** @type {?} */ ({
handle: (/**
* @return {?}
*/
() => res$),
})));
return chain.handle(req).pipe(delay(config.delay));
}
}
return res$.pipe(delay(config.delay));
}
}
MockInterceptor.decorators = [
{ type: Injectable }
];
/** @nocollapse */
MockInterceptor.ctorParameters = () => [
{ type: Injector }
];
if (false) {
/**
* @type {?}
* @private
*/
MockInterceptor.prototype.injector;
}
/**
* @fileoverview added by tsickle
* Generated from: src/mock.module.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class LxlibMockModule {
/**
* @param {?} config
* @return {?}
*/
static forRoot(config) {
return {
ngModule: LxlibMockModule,
providers: [
MockService,
{ provide: LxlibMockConfig, useValue: config },
{ provide: HTTP_INTERCEPTORS, useClass: MockInterceptor, multi: true },
],
};
}
/**
* @return {?}
*/
static forChild() {
return {
ngModule: LxlibMockModule,
providers: [{ provide: HTTP_INTERCEPTORS, useClass: MockInterceptor, multi: true }],
};
}
}
LxlibMockModule.decorators = [
{ type: NgModule, args: [{},] }
];
/**
* @fileoverview added by tsickle
* Generated from: public_api.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* Generated from: mock.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
export { LxlibMockConfig, LxlibMockModule, MockInterceptor, MockService, MockStatusError };
//# sourceMappingURL=mock.js.map