vite-plugin-mock-dev-server 1.9.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,810 +0,0 @@
1
- const require_dist = require('./dist-DrfpZ4UT.cjs');
2
- const picocolors = require_dist.__toESM(require("picocolors"));
3
- const node_fs = require_dist.__toESM(require("node:fs"));
4
- const node_path = require_dist.__toESM(require("node:path"));
5
- const node_url = require_dist.__toESM(require("node:url"));
6
- const node_os = require_dist.__toESM(require("node:os"));
7
- const node_querystring = require_dist.__toESM(require("node:querystring"));
8
- const debug = require_dist.__toESM(require("debug"));
9
- const path_to_regexp = require_dist.__toESM(require("path-to-regexp"));
10
- const node_buffer = require_dist.__toESM(require("node:buffer"));
11
- const cookies = require_dist.__toESM(require("cookies"));
12
- const http_status = require_dist.__toESM(require("http-status"));
13
- const mime_types = require_dist.__toESM(require("mime-types"));
14
- const co_body = require_dist.__toESM(require("co-body"));
15
- const formidable = require_dist.__toESM(require("formidable"));
16
- const ws = require_dist.__toESM(require("ws"));
17
-
18
- //#region src/core/utils.ts
19
- function isStream(stream) {
20
- return stream !== null && typeof stream === "object" && typeof stream.pipe === "function";
21
- }
22
- function isReadableStream(stream) {
23
- return isStream(stream) && stream.readable !== false && typeof stream._read === "function" && typeof stream._readableState === "object";
24
- }
25
- const debug$1 = (0, debug.default)("vite:mock-dev-server");
26
- function lookupFile(dir, formats, options) {
27
- for (const format of formats) {
28
- const fullPath = node_path.default.join(dir, format);
29
- if (node_fs.default.existsSync(fullPath) && node_fs.default.statSync(fullPath).isFile()) {
30
- const result = options?.pathOnly ? fullPath : node_fs.default.readFileSync(fullPath, "utf-8");
31
- if (!options?.predicate || options.predicate(result)) return result;
32
- }
33
- }
34
- const parentDir = node_path.default.dirname(dir);
35
- if (parentDir !== dir && (!options?.rootDir || parentDir.startsWith(options?.rootDir))) return lookupFile(parentDir, formats, options);
36
- }
37
- function ensureProxies(serverProxy = {}) {
38
- const httpProxies = [];
39
- const wsProxies = [];
40
- Object.keys(serverProxy).forEach((key) => {
41
- const value = serverProxy[key];
42
- if (typeof value === "string" || !value.ws && !value.target?.toString().startsWith("ws:") && !value.target?.toString().startsWith("wss:")) httpProxies.push(key);
43
- else wsProxies.push(key);
44
- });
45
- return {
46
- httpProxies,
47
- wsProxies
48
- };
49
- }
50
- function doesProxyContextMatchUrl(context, url) {
51
- return context[0] === "^" && new RegExp(context).test(url) || url.startsWith(context);
52
- }
53
- function parseParams(pattern, url) {
54
- const urlMatch = (0, path_to_regexp.match)(pattern, { decode: decodeURIComponent })(url) || { params: {} };
55
- return urlMatch.params || {};
56
- }
57
- /**
58
- * nodejs 从 19.0.0 开始 弃用 url.parse,因此使用 url.parse 来解析 可能会报错,
59
- * 使用 URL 来解析
60
- */
61
- function urlParse(input) {
62
- const url = new node_url.URL(input, "http://example.com");
63
- const pathname = decodeURIComponent(url.pathname);
64
- const query = (0, node_querystring.parse)(url.search.replace(/^\?/, ""));
65
- return {
66
- pathname,
67
- query
68
- };
69
- }
70
- const windowsSlashRE = /\\/g;
71
- const isWindows = node_os.default.platform() === "win32";
72
- function slash(p) {
73
- return p.replace(windowsSlashRE, "/");
74
- }
75
- function normalizePath(id) {
76
- return node_path.default.posix.normalize(isWindows ? slash(id) : id);
77
- }
78
-
79
- //#endregion
80
- //#region src/core/matchingWeight.ts
81
- const tokensCache = {};
82
- function getTokens(rule) {
83
- if (tokensCache[rule]) return tokensCache[rule];
84
- const tks = (0, path_to_regexp.parse)(rule);
85
- const tokens = [];
86
- for (const tk of tks) if (!require_dist.isString(tk)) tokens.push(tk);
87
- else {
88
- const hasPrefix = tk[0] === "/";
89
- const subTks = hasPrefix ? tk.slice(1).split("/") : tk.split("/");
90
- tokens.push(`${hasPrefix ? "/" : ""}${subTks[0]}`, ...subTks.slice(1).map((t) => `/${t}`));
91
- }
92
- tokensCache[rule] = tokens;
93
- return tokens;
94
- }
95
- function getHighest(rules) {
96
- let weights = rules.map((rule) => getTokens(rule).length);
97
- weights = weights.length === 0 ? [1] : weights;
98
- return Math.max(...weights) + 2;
99
- }
100
- function sortFn(rule) {
101
- const tokens = getTokens(rule);
102
- let w = 0;
103
- for (let i = 0; i < tokens.length; i++) {
104
- const token = tokens[i];
105
- if (!require_dist.isString(token)) w += 10 ** (i + 1);
106
- w += 10 ** (i + 1);
107
- }
108
- return w;
109
- }
110
- function preSort(rules) {
111
- let matched = [];
112
- const preMatch = [];
113
- for (const rule of rules) {
114
- const tokens = getTokens(rule);
115
- const len = tokens.filter((token) => typeof token !== "string").length;
116
- if (!preMatch[len]) preMatch[len] = [];
117
- preMatch[len].push(rule);
118
- }
119
- for (const match$1 of preMatch.filter((v) => v && v.length > 0)) matched = [...matched, ...require_dist.sortBy(match$1, sortFn).reverse()];
120
- return matched;
121
- }
122
- function defaultPriority(rules) {
123
- const highest = getHighest(rules);
124
- return require_dist.sortBy(rules, (rule) => {
125
- const tokens = getTokens(rule);
126
- const dym = tokens.filter((token) => typeof token !== "string");
127
- if (dym.length === 0) return 0;
128
- let weight = dym.length;
129
- let exp = 0;
130
- for (let i = 0; i < tokens.length; i++) {
131
- const token = tokens[i];
132
- const isDynamic = !require_dist.isString(token);
133
- const { pattern = "", modifier, prefix, name } = isDynamic ? token : {};
134
- const isGlob = pattern && pattern.includes(".*");
135
- const isSlash = prefix === "/";
136
- const isNamed = require_dist.isString(name);
137
- exp += isDynamic && isSlash ? 1 : 0;
138
- if (i === tokens.length - 1 && isGlob) weight += 5 * 10 ** (tokens.length === 1 ? highest + 1 : highest);
139
- else if (isGlob) weight += 3 * 10 ** (highest - 1);
140
- else if (pattern) if (isSlash) weight += (isNamed ? 2 : 1) * 10 ** (exp + 1);
141
- else weight -= 1 * 10 ** exp;
142
- if (modifier === "+") weight += 1 * 10 ** (highest - 1);
143
- if (modifier === "*") weight += 1 * 10 ** (highest - 1) + 1;
144
- if (modifier === "?") weight += 1 * 10 ** (exp + (isSlash ? 1 : 0));
145
- }
146
- return weight;
147
- });
148
- }
149
- function matchingWeight(rules, url, priority) {
150
- let matched = defaultPriority(preSort(rules.filter((rule) => (0, path_to_regexp.pathToRegexp)(rule).test(url))));
151
- const { global = [], special = {} } = priority;
152
- if (global.length === 0 && require_dist.isEmptyObject(special) || matched.length === 0) return matched;
153
- const [statics, dynamics] = twoPartMatch(matched);
154
- const globalMatch = global.filter((rule) => dynamics.includes(rule));
155
- if (globalMatch.length > 0) matched = require_dist.uniq([
156
- ...statics,
157
- ...globalMatch,
158
- ...dynamics
159
- ]);
160
- if (require_dist.isEmptyObject(special)) return matched;
161
- const specialRule = Object.keys(special).filter((rule) => matched.includes(rule))[0];
162
- if (!specialRule) return matched;
163
- const options = special[specialRule];
164
- const { rules: lowerRules, when } = require_dist.isArray(options) ? {
165
- rules: options,
166
- when: []
167
- } : options;
168
- if (lowerRules.includes(matched[0])) {
169
- if (when.length === 0 || when.some((path$1) => (0, path_to_regexp.pathToRegexp)(path$1).test(url))) matched = require_dist.uniq([specialRule, ...matched]);
170
- }
171
- return matched;
172
- }
173
- function twoPartMatch(rules) {
174
- const statics = [];
175
- const dynamics = [];
176
- for (const rule of rules) {
177
- const tokens = getTokens(rule);
178
- const dym = tokens.filter((token) => typeof token !== "string");
179
- if (dym.length > 0) dynamics.push(rule);
180
- else statics.push(rule);
181
- }
182
- return [statics, dynamics];
183
- }
184
-
185
- //#endregion
186
- //#region src/core/parseReqBody.ts
187
- const DEFAULT_FORMIDABLE_OPTIONS = {
188
- keepExtensions: true,
189
- filename(name, ext, part) {
190
- return part?.originalFilename || `${name}.${Date.now()}${ext ? `.${ext}` : ""}`;
191
- }
192
- };
193
- async function parseReqBody(req, formidableOptions, bodyParserOptions = {}) {
194
- const method = req.method.toUpperCase();
195
- if (["HEAD", "OPTIONS"].includes(method)) return void 0;
196
- const type = req.headers["content-type"]?.toLocaleLowerCase() || "";
197
- const { limit, formLimit, jsonLimit, textLimit,...rest } = bodyParserOptions;
198
- try {
199
- if (type.startsWith("application/json")) return await co_body.default.json(req, {
200
- limit: jsonLimit || limit,
201
- ...rest
202
- });
203
- if (type.startsWith("application/x-www-form-urlencoded")) return await co_body.default.form(req, {
204
- limit: formLimit || limit,
205
- ...rest
206
- });
207
- if (type.startsWith("text/plain")) return await co_body.default.text(req, {
208
- limit: textLimit || limit,
209
- ...rest
210
- });
211
- if (type.startsWith("multipart/form-data")) return await parseMultipart(req, formidableOptions);
212
- } catch (e) {
213
- console.error(e);
214
- }
215
- return void 0;
216
- }
217
- async function parseMultipart(req, options) {
218
- const form = (0, formidable.default)({
219
- ...DEFAULT_FORMIDABLE_OPTIONS,
220
- ...options
221
- });
222
- return new Promise((resolve, reject) => {
223
- form.parse(req, (error, fields, files) => {
224
- if (error) {
225
- reject(error);
226
- return;
227
- }
228
- resolve({
229
- ...fields,
230
- ...files
231
- });
232
- });
233
- });
234
- }
235
-
236
- //#endregion
237
- //#region src/core/requestRecovery.ts
238
- const cache = /* @__PURE__ */ new WeakMap();
239
- function collectRequest(req) {
240
- const chunks = [];
241
- req.addListener("data", (chunk) => {
242
- chunks.push(node_buffer.Buffer.from(chunk));
243
- });
244
- req.addListener("end", () => {
245
- if (chunks.length) cache.set(req, node_buffer.Buffer.concat(chunks));
246
- });
247
- }
248
- /**
249
- * vite 在 proxy 配置中,允许通过 configure 访问 http-proxy 实例,
250
- * 通过 http-proxy 的 proxyReq 事件,重新写入请求流
251
- */
252
- function recoverRequest(config) {
253
- if (!config.server) return;
254
- const proxies = config.server.proxy || {};
255
- Object.keys(proxies).forEach((key) => {
256
- const target = proxies[key];
257
- const options = typeof target === "string" ? { target } : target;
258
- if (options.ws) return;
259
- const { configure,...rest } = options;
260
- proxies[key] = {
261
- ...rest,
262
- configure(proxy, options$1) {
263
- configure?.(proxy, options$1);
264
- proxy.on("proxyReq", (proxyReq, req) => {
265
- const buffer = cache.get(req);
266
- if (buffer) {
267
- cache.delete(req);
268
- /**
269
- * 使用 http-proxy 的 agent 配置会提前写入代理请求流
270
- * https://github.com/http-party/node-http-proxy/issues/1287
271
- */
272
- if (!proxyReq.headersSent) proxyReq.setHeader("Content-Length", buffer.byteLength);
273
- if (!proxyReq.writableEnded) proxyReq.write(buffer);
274
- }
275
- });
276
- }
277
- };
278
- });
279
- }
280
-
281
- //#endregion
282
- //#region src/core/validator.ts
283
- function validate(request, validator) {
284
- return isObjectSubset(request.headers, validator.headers) && isObjectSubset(request.body, validator.body) && isObjectSubset(request.params, validator.params) && isObjectSubset(request.query, validator.query) && isObjectSubset(request.refererQuery, validator.refererQuery);
285
- }
286
- /**
287
- * Checks if target object is a subset of source object.
288
- * That is, all properties and their corresponding values in target exist in source.
289
- *
290
- * 深度比较两个对象之间,target 是否属于 source 的子集,
291
- * 即 target 的所有属性和对应的值,都在 source 中,
292
- */
293
- function isObjectSubset(source, target) {
294
- if (!target) return true;
295
- for (const key in target) if (!isIncluded(source[key], target[key])) return false;
296
- return true;
297
- }
298
- function isIncluded(source, target) {
299
- if (require_dist.isArray(source) && require_dist.isArray(target)) {
300
- const seen = /* @__PURE__ */ new Set();
301
- return target.every((ti) => source.some((si, i) => {
302
- if (seen.has(i)) return false;
303
- const included = isIncluded(si, ti);
304
- if (included) seen.add(i);
305
- return included;
306
- }));
307
- }
308
- if (require_dist.isPlainObject(source) && require_dist.isPlainObject(target)) return isObjectSubset(source, target);
309
- return Object.is(source, target);
310
- }
311
-
312
- //#endregion
313
- //#region src/core/baseMiddleware.ts
314
- function baseMiddleware(compiler, { formidableOptions = {}, bodyParserOptions = {}, proxies, cookiesOptions, logger, priority = {} }) {
315
- return async function(req, res, next) {
316
- const startTime = require_dist.timestamp();
317
- const { query, pathname } = urlParse(req.url);
318
- if (!pathname || proxies.length === 0 || !proxies.some((context) => doesProxyContextMatchUrl(context, req.url))) return next();
319
- const mockData = compiler.mockData;
320
- const mockUrls = matchingWeight(Object.keys(mockData), pathname, priority);
321
- if (mockUrls.length === 0) return next();
322
- collectRequest(req);
323
- const { query: refererQuery } = urlParse(req.headers.referer || "");
324
- const reqBody = await parseReqBody(req, formidableOptions, bodyParserOptions);
325
- const cookies$1 = new cookies.default(req, res, cookiesOptions);
326
- const getCookie = cookies$1.get.bind(cookies$1);
327
- const method = req.method.toUpperCase();
328
- let mock;
329
- let _mockUrl;
330
- for (const mockUrl of mockUrls) {
331
- mock = fineMock(mockData[mockUrl], logger, {
332
- pathname,
333
- method,
334
- request: {
335
- query,
336
- refererQuery,
337
- body: reqBody,
338
- headers: req.headers,
339
- getCookie
340
- }
341
- });
342
- if (mock) {
343
- _mockUrl = mockUrl;
344
- break;
345
- }
346
- }
347
- if (!mock) {
348
- const matched = mockUrls.map((m) => m === _mockUrl ? picocolors.default.underline(picocolors.default.bold(m)) : picocolors.default.dim(m)).join(", ");
349
- logger.warn(`${picocolors.default.green(pathname)} matches ${matched} , but mock data is not found.`);
350
- return next();
351
- }
352
- const request = req;
353
- const response = res;
354
- request.body = reqBody;
355
- request.query = query;
356
- request.refererQuery = refererQuery;
357
- request.params = parseParams(mock.url, pathname);
358
- request.getCookie = getCookie;
359
- response.setCookie = cookies$1.set.bind(cookies$1);
360
- const { body, delay, type = "json", response: responseFn, status = 200, statusText, log: logLevel, __filepath__: filepath } = mock;
361
- responseStatus(response, status, statusText);
362
- await provideHeaders(request, response, mock, logger);
363
- await provideCookies(request, response, mock, logger);
364
- logger.info(requestLog(request, filepath), logLevel);
365
- logger.debug(`${picocolors.default.magenta("DEBUG")} ${picocolors.default.underline(pathname)} matches: [ ${mockUrls.map((m) => m === _mockUrl ? picocolors.default.underline(picocolors.default.bold(m)) : picocolors.default.dim(m)).join(", ")} ]\n`);
366
- if (body) {
367
- try {
368
- const content = require_dist.isFunction(body) ? await body(request) : body;
369
- await realDelay(startTime, delay);
370
- sendData(response, content, type);
371
- } catch (e) {
372
- logger.error(`${picocolors.default.red(`mock error at ${pathname}`)}\n${e}\n at body (${picocolors.default.underline(filepath)})`, logLevel);
373
- responseStatus(response, 500);
374
- res.end("");
375
- }
376
- return;
377
- }
378
- if (responseFn) {
379
- try {
380
- await realDelay(startTime, delay);
381
- await responseFn(request, response, next);
382
- } catch (e) {
383
- logger.error(`${picocolors.default.red(`mock error at ${pathname}`)}\n${e}\n at response (${picocolors.default.underline(filepath)})`, logLevel);
384
- responseStatus(response, 500);
385
- res.end("");
386
- }
387
- return;
388
- }
389
- res.end("");
390
- };
391
- }
392
- function fineMock(mockList, logger, { pathname, method, request }) {
393
- return mockList.find((mock) => {
394
- if (!pathname || !mock || !mock.url || mock.ws === true) return false;
395
- const methods = mock.method ? require_dist.isArray(mock.method) ? mock.method : [mock.method] : ["GET", "POST"];
396
- if (!methods.includes(method)) return false;
397
- const hasMock = (0, path_to_regexp.pathToRegexp)(mock.url).test(pathname);
398
- if (hasMock && mock.validator) {
399
- const params = parseParams(mock.url, pathname);
400
- if (require_dist.isFunction(mock.validator)) return mock.validator({
401
- params,
402
- ...request
403
- });
404
- else try {
405
- return validate({
406
- params,
407
- ...request
408
- }, mock.validator);
409
- } catch (e) {
410
- const file = mock.__filepath__;
411
- logger.error(`${picocolors.default.red(`mock error at ${pathname}`)}\n${e}\n at validator (${picocolors.default.underline(file)})`, mock.log);
412
- return false;
413
- }
414
- }
415
- return hasMock;
416
- });
417
- }
418
- function responseStatus(response, status = 200, statusText) {
419
- response.statusCode = status;
420
- response.statusMessage = statusText || getHTTPStatusText(status);
421
- }
422
- async function provideHeaders(req, res, mock, logger) {
423
- const { headers, type = "json" } = mock;
424
- const filepath = mock.__filepath__;
425
- const contentType = mime_types.contentType(type) || mime_types.contentType(mime_types.lookup(type) || "");
426
- if (contentType) res.setHeader("Content-Type", contentType);
427
- res.setHeader("Cache-Control", "no-cache,max-age=0");
428
- res.setHeader("X-Mock-Power-By", "vite-plugin-mock-dev-server");
429
- if (filepath) res.setHeader("X-File-Path", filepath);
430
- if (!headers) return;
431
- try {
432
- const raw = require_dist.isFunction(headers) ? await headers(req) : headers;
433
- Object.keys(raw).forEach((key) => {
434
- res.setHeader(key, raw[key]);
435
- });
436
- } catch (e) {
437
- logger.error(`${picocolors.default.red(`mock error at ${req.url.split("?")[0]}`)}\n${e}\n at headers (${picocolors.default.underline(filepath)})`, mock.log);
438
- }
439
- }
440
- async function provideCookies(req, res, mock, logger) {
441
- const { cookies: cookies$1 } = mock;
442
- const filepath = mock.__filepath__;
443
- if (!cookies$1) return;
444
- try {
445
- const raw = require_dist.isFunction(cookies$1) ? await cookies$1(req) : cookies$1;
446
- Object.keys(raw).forEach((key) => {
447
- const cookie = raw[key];
448
- if (require_dist.isArray(cookie)) {
449
- const [value, options] = cookie;
450
- res.setCookie(key, value, options);
451
- } else res.setCookie(key, cookie);
452
- });
453
- } catch (e) {
454
- logger.error(`${picocolors.default.red(`mock error at ${req.url.split("?")[0]}`)}\n${e}\n at cookies (${picocolors.default.underline(filepath)})`, mock.log);
455
- }
456
- }
457
- function sendData(res, raw, type) {
458
- if (isReadableStream(raw)) raw.pipe(res);
459
- else if (node_buffer.Buffer.isBuffer(raw)) res.end(type === "text" || type === "json" ? raw.toString("utf-8") : raw);
460
- else {
461
- const content = typeof raw === "string" ? raw : JSON.stringify(raw);
462
- res.end(type === "buffer" ? node_buffer.Buffer.from(content) : content);
463
- }
464
- }
465
- async function realDelay(startTime, delay) {
466
- if (!delay || typeof delay === "number" && delay <= 0 || require_dist.isArray(delay) && delay.length !== 2) return;
467
- let realDelay$1 = 0;
468
- if (require_dist.isArray(delay)) {
469
- const [min, max] = delay;
470
- realDelay$1 = require_dist.random(min, max);
471
- } else realDelay$1 = delay - (require_dist.timestamp() - startTime);
472
- if (realDelay$1 > 0) await require_dist.sleep(realDelay$1);
473
- }
474
- function getHTTPStatusText(status) {
475
- return http_status.default[status] || "Unknown";
476
- }
477
- function requestLog(request, filepath) {
478
- const { url, method, query, params, body } = request;
479
- let { pathname } = new URL(url, "http://example.com");
480
- pathname = picocolors.default.green(decodeURIComponent(pathname));
481
- const format = (prefix, data) => {
482
- return !data || require_dist.isEmptyObject(data) ? "" : ` ${picocolors.default.gray(`${prefix}:`)}${JSON.stringify(data)}`;
483
- };
484
- const ms = picocolors.default.magenta(picocolors.default.bold(method));
485
- const qs = format("query", query);
486
- const ps = format("params", params);
487
- const bs = format("body", body);
488
- const file = ` ${picocolors.default.dim(picocolors.default.underline(`(${filepath})`))}`;
489
- return `${ms} ${pathname}${qs}${ps}${bs}${file}`;
490
- }
491
-
492
- //#endregion
493
- //#region src/core/transform.ts
494
- function transformRawData(raw, __filepath__) {
495
- let mockConfig;
496
- if (require_dist.isArray(raw)) mockConfig = raw.map((item) => ({
497
- ...item,
498
- __filepath__
499
- }));
500
- else if ("url" in raw) mockConfig = {
501
- ...raw,
502
- __filepath__
503
- };
504
- else {
505
- mockConfig = [];
506
- Object.keys(raw).forEach((key) => {
507
- const data = raw[key];
508
- if (require_dist.isArray(data)) mockConfig.push(...data.map((item) => ({
509
- ...item,
510
- __filepath__
511
- })));
512
- else mockConfig.push({
513
- ...data,
514
- __filepath__
515
- });
516
- });
517
- }
518
- return mockConfig;
519
- }
520
- function transformMockData(mockList) {
521
- const list = [];
522
- for (const [, handle] of mockList.entries()) if (handle) list.push(...require_dist.toArray(handle));
523
- const mocks = {};
524
- list.filter((mock) => require_dist.isPlainObject(mock) && mock.enabled !== false && mock.url).forEach((mock) => {
525
- const { pathname, query } = urlParse(mock.url);
526
- const list$1 = mocks[pathname] ??= [];
527
- const current = {
528
- ...mock,
529
- url: pathname
530
- };
531
- if (current.ws !== true) {
532
- const validator = current.validator;
533
- if (!require_dist.isEmptyObject(query)) if (require_dist.isFunction(validator)) current.validator = function(request) {
534
- return isObjectSubset(request.query, query) && validator(request);
535
- };
536
- else if (validator) {
537
- current.validator = { ...validator };
538
- current.validator.query = current.validator.query ? {
539
- ...query,
540
- ...current.validator.query
541
- } : query;
542
- } else current.validator = { query };
543
- }
544
- list$1.push(current);
545
- });
546
- Object.keys(mocks).forEach((key) => {
547
- mocks[key] = sortByValidator(mocks[key]);
548
- });
549
- return mocks;
550
- }
551
- function sortByValidator(mocks) {
552
- return require_dist.sortBy(mocks, (item) => {
553
- if (item.ws === true) return 0;
554
- const { validator } = item;
555
- if (!validator || require_dist.isEmptyObject(validator)) return 2;
556
- if (require_dist.isFunction(validator)) return 0;
557
- const count = Object.keys(validator).reduce((prev, key) => prev + keysCount(validator[key]), 0);
558
- return 1 / count;
559
- });
560
- }
561
- function keysCount(obj) {
562
- if (!obj) return 0;
563
- return Object.keys(obj).length;
564
- }
565
-
566
- //#endregion
567
- //#region src/core/ws.ts
568
- /**
569
- * mock websocket
570
- */
571
- function mockWebSocket(compiler, server, { wsProxies: proxies, cookiesOptions, logger }) {
572
- const hmrMap = /* @__PURE__ */ new Map();
573
- const poolMap = /* @__PURE__ */ new Map();
574
- const wssContextMap = /* @__PURE__ */ new WeakMap();
575
- const getWssMap = (mockUrl) => {
576
- let wssMap = poolMap.get(mockUrl);
577
- if (!wssMap) poolMap.set(mockUrl, wssMap = /* @__PURE__ */ new Map());
578
- return wssMap;
579
- };
580
- const getWss = (wssMap, pathname) => {
581
- let wss = wssMap.get(pathname);
582
- if (!wss) wssMap.set(pathname, wss = new ws.WebSocketServer({ noServer: true }));
583
- return wss;
584
- };
585
- const addHmr = (filepath, mockUrl) => {
586
- let urlList = hmrMap.get(filepath);
587
- if (!urlList) hmrMap.set(filepath, urlList = /* @__PURE__ */ new Set());
588
- urlList.add(mockUrl);
589
- };
590
- const setupWss = (wssMap, wss, mock, context, pathname, filepath) => {
591
- try {
592
- mock.setup?.(wss, context);
593
- wss.on("close", () => wssMap.delete(pathname));
594
- wss.on("error", (e) => {
595
- logger.error(`${picocolors.default.red(`WebSocket mock error at ${wss.path}`)}\n${e}\n at setup (${filepath})`, mock.log);
596
- });
597
- } catch (e) {
598
- logger.error(`${picocolors.default.red(`WebSocket mock error at ${wss.path}`)}\n${e}\n at setup (${filepath})`, mock.log);
599
- }
600
- };
601
- const emitConnection = (wss, ws$1, req, connectionList) => {
602
- wss.emit("connection", ws$1, req);
603
- ws$1.on("close", () => {
604
- const i = connectionList.findIndex((item) => item.ws === ws$1);
605
- if (i !== -1) connectionList.splice(i, 1);
606
- });
607
- };
608
- const restartWss = (wssMap, wss, mock, pathname, filepath) => {
609
- const { cleanupList, connectionList, context } = wssContextMap.get(wss);
610
- cleanupRunner(cleanupList);
611
- connectionList.forEach(({ ws: ws$1 }) => ws$1.removeAllListeners());
612
- wss.removeAllListeners();
613
- setupWss(wssMap, wss, mock, context, pathname, filepath);
614
- connectionList.forEach(({ ws: ws$1, req }) => emitConnection(wss, ws$1, req, connectionList));
615
- };
616
- compiler.on?.("mock:update-end", (filepath) => {
617
- if (!hmrMap.has(filepath)) return;
618
- const mockUrlList = hmrMap.get(filepath);
619
- if (!mockUrlList) return;
620
- for (const mockUrl of mockUrlList.values()) for (const mock of compiler.mockData[mockUrl]) {
621
- if (!mock.ws || mock.__filepath__ !== filepath) return;
622
- const wssMap = getWssMap(mockUrl);
623
- for (const [pathname, wss] of wssMap.entries()) restartWss(wssMap, wss, mock, pathname, filepath);
624
- }
625
- });
626
- server?.on("upgrade", (req, socket, head) => {
627
- const { pathname, query } = urlParse(req.url);
628
- if (!pathname || proxies.length === 0 || !proxies.some((context) => doesProxyContextMatchUrl(context, req.url))) return;
629
- const mockData = compiler.mockData;
630
- const mockUrl = Object.keys(mockData).find((key) => {
631
- return (0, path_to_regexp.pathToRegexp)(key).test(pathname);
632
- });
633
- if (!mockUrl) return;
634
- const mock = mockData[mockUrl].find((mock$1) => {
635
- return mock$1.url && mock$1.ws && (0, path_to_regexp.pathToRegexp)(mock$1.url).test(pathname);
636
- });
637
- if (!mock) return;
638
- const filepath = mock.__filepath__;
639
- addHmr(filepath, mockUrl);
640
- const wssMap = getWssMap(mockUrl);
641
- const wss = getWss(wssMap, pathname);
642
- let wssContext = wssContextMap.get(wss);
643
- if (!wssContext) {
644
- const cleanupList = [];
645
- const context = { onCleanup: (cleanup) => cleanupList.push(cleanup) };
646
- wssContext = {
647
- cleanupList,
648
- context,
649
- connectionList: []
650
- };
651
- wssContextMap.set(wss, wssContext);
652
- setupWss(wssMap, wss, mock, context, pathname, filepath);
653
- }
654
- const request = req;
655
- const cookies$1 = new cookies.default(req, req, cookiesOptions);
656
- const { query: refererQuery } = urlParse(req.headers.referer || "");
657
- request.query = query;
658
- request.refererQuery = refererQuery;
659
- request.params = parseParams(mockUrl, pathname);
660
- request.getCookie = cookies$1.get.bind(cookies$1);
661
- wss.handleUpgrade(request, socket, head, (ws$1) => {
662
- logger.info(`${picocolors.default.magenta(picocolors.default.bold("WebSocket"))} ${picocolors.default.green(req.url)} connected ${picocolors.default.dim(`(${filepath})`)}`, mock.log);
663
- wssContext.connectionList.push({
664
- req: request,
665
- ws: ws$1
666
- });
667
- emitConnection(wss, ws$1, request, wssContext.connectionList);
668
- });
669
- });
670
- server?.on("close", () => {
671
- for (const wssMap of poolMap.values()) {
672
- for (const wss of wssMap.values()) {
673
- const wssContext = wssContextMap.get(wss);
674
- cleanupRunner(wssContext.cleanupList);
675
- wss.close();
676
- }
677
- wssMap.clear();
678
- }
679
- poolMap.clear();
680
- hmrMap.clear();
681
- });
682
- }
683
- function cleanupRunner(cleanupList) {
684
- let cleanup;
685
- while (cleanup = cleanupList.shift()) cleanup?.();
686
- }
687
-
688
- //#endregion
689
- //#region src/core/logger.ts
690
- const logLevels = {
691
- silent: 0,
692
- error: 1,
693
- warn: 2,
694
- info: 3,
695
- debug: 4
696
- };
697
- function createLogger(prefix, defaultLevel = "info") {
698
- prefix = `[${prefix}]`;
699
- function output(type, msg, level) {
700
- level = require_dist.isBoolean(level) ? level ? defaultLevel : "error" : level;
701
- const thresh = logLevels[level];
702
- if (thresh >= logLevels[type]) {
703
- const method = type === "info" || type === "debug" ? "log" : type;
704
- const tag = type === "debug" ? picocolors.default.magenta(picocolors.default.bold(prefix)) : type === "info" ? picocolors.default.cyan(picocolors.default.bold(prefix)) : type === "warn" ? picocolors.default.yellow(picocolors.default.bold(prefix)) : picocolors.default.red(picocolors.default.bold(prefix));
705
- const format = `${picocolors.default.dim((/* @__PURE__ */ new Date()).toLocaleTimeString())} ${tag} ${msg}`;
706
- console[method](format);
707
- }
708
- }
709
- const logger = {
710
- debug(msg, level = defaultLevel) {
711
- output("debug", msg, level);
712
- },
713
- info(msg, level = defaultLevel) {
714
- output("info", msg, level);
715
- },
716
- warn(msg, level = defaultLevel) {
717
- output("warn", msg, level);
718
- },
719
- error(msg, level = defaultLevel) {
720
- output("error", msg, level);
721
- }
722
- };
723
- return logger;
724
- }
725
-
726
- //#endregion
727
- Object.defineProperty(exports, 'baseMiddleware', {
728
- enumerable: true,
729
- get: function () {
730
- return baseMiddleware;
731
- }
732
- });
733
- Object.defineProperty(exports, 'createLogger', {
734
- enumerable: true,
735
- get: function () {
736
- return createLogger;
737
- }
738
- });
739
- Object.defineProperty(exports, 'debug', {
740
- enumerable: true,
741
- get: function () {
742
- return debug$1;
743
- }
744
- });
745
- Object.defineProperty(exports, 'doesProxyContextMatchUrl', {
746
- enumerable: true,
747
- get: function () {
748
- return doesProxyContextMatchUrl;
749
- }
750
- });
751
- Object.defineProperty(exports, 'ensureProxies', {
752
- enumerable: true,
753
- get: function () {
754
- return ensureProxies;
755
- }
756
- });
757
- Object.defineProperty(exports, 'logLevels', {
758
- enumerable: true,
759
- get: function () {
760
- return logLevels;
761
- }
762
- });
763
- Object.defineProperty(exports, 'lookupFile', {
764
- enumerable: true,
765
- get: function () {
766
- return lookupFile;
767
- }
768
- });
769
- Object.defineProperty(exports, 'mockWebSocket', {
770
- enumerable: true,
771
- get: function () {
772
- return mockWebSocket;
773
- }
774
- });
775
- Object.defineProperty(exports, 'normalizePath', {
776
- enumerable: true,
777
- get: function () {
778
- return normalizePath;
779
- }
780
- });
781
- Object.defineProperty(exports, 'recoverRequest', {
782
- enumerable: true,
783
- get: function () {
784
- return recoverRequest;
785
- }
786
- });
787
- Object.defineProperty(exports, 'sortByValidator', {
788
- enumerable: true,
789
- get: function () {
790
- return sortByValidator;
791
- }
792
- });
793
- Object.defineProperty(exports, 'transformMockData', {
794
- enumerable: true,
795
- get: function () {
796
- return transformMockData;
797
- }
798
- });
799
- Object.defineProperty(exports, 'transformRawData', {
800
- enumerable: true,
801
- get: function () {
802
- return transformRawData;
803
- }
804
- });
805
- Object.defineProperty(exports, 'urlParse', {
806
- enumerable: true,
807
- get: function () {
808
- return urlParse;
809
- }
810
- });