UNPKG

ohayolibs

Version:

Ohayo is a set of essential modules for ohayojp.

141 lines (123 loc) 4.1 kB
import { Injectable, OnDestroy } from '@angular/core'; import { OhayoConfigService, OhayoMockConfig } from '@ohayo/util'; import { NzSafeAny } from 'ng-zorro-antd/core/types'; import { MockCachedRule, MockRule } from './interface'; import { MOCK_DEFULAT_CONFIG } from './mock.config'; @Injectable({ providedIn: 'root' }) export class MockService implements OnDestroy { private cached: MockCachedRule[] = []; readonly config: OhayoMockConfig; constructor(cogSrv: OhayoConfigService) { this.config = cogSrv.merge('mock', MOCK_DEFULAT_CONFIG)!; this.applyMock(); delete this.config.data; } // #region parse rule private applyMock(): void { this.cached = []; try { this.realApplyMock(); } catch (e) { this.outputError(e); } } private realApplyMock(): void { const data = this.config.data; if (!data) return; Object.keys(data).forEach((key: string) => { const rules = data[key]; if (!rules) return; Object.keys(rules).forEach((ruleKey: string) => { 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}`); } 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`); } const item = this.cached.find(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((a, b) => (b.martcher || '').toString().length - (a.martcher || '').toString().length); } private genRule(key: string, callback: any): MockCachedRule { let method = 'GET'; let url = key; if (key.indexOf(' ') > -1) { const splited = key.split(' '); method = splited[0].toLowerCase(); url = splited[1]; } let martcher: RegExp | null = null; let segments: string[] = []; if (~url.indexOf(':')) { segments = url! .split('/') .filter(segment => segment.startsWith(':')) .map(v => v.substring(1)); const reStr = url! .split('/') .map(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 outputError(error: NzSafeAny): void { const filePath = error.message.split(': ')[0]; const errors = (error.stack as string) .split('\n') .filter(line => line.trim().indexOf('at ') !== 0) .map(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 getRule(method: string, url: string): MockRule | null { method = (method || 'GET').toUpperCase(); const params: NzSafeAny = {}; const list = this.cached.filter(w => w.method === method && (w.martcher ? w.martcher.test(url) : w.url === url)); if (list.length === 0) return null; const ret = list.find(w => w.url === url) || list[0]; if (ret.martcher) { const execArr = ret.martcher.exec(url); execArr!.slice(1).map((value: string, index: number) => { params[ret.segments[index]] = value; }); } return { url, method: ret.method, params, callback: ret.callback, }; } clearCache(): void { this.cached = []; } get rules(): MockCachedRule[] { return this.cached; } ngOnDestroy(): void { this.clearCache(); } }