rspack-plugin-mock 1.3.0 → 2.1.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,8 +1,8 @@
1
- import { _ as WebSocketSetupContext, a as LogType, c as MockMatchPriority, d as MockRequest, f as MockResponse, g as ServerBuildOption, h as ResponseBody, i as LogLevel, l as MockMatchSpecialPriority, m as MockWebsocketItem, n as ExtraRequest, o as Method, p as MockServerPluginOptions, r as FormidableFile, s as MockHttpItem, t as BodyParserOptions, u as MockOptions } from "./types-Bt_OTa7I.mjs";
2
- import { Transform } from "node:stream";
1
+ import { A as ResponseBody, C as HandleFunction, D as MockResponse, E as MockRequest, M as CookiesOption, N as GetCookieOption, O as NextFunction, P as SetCookieOption, S as ExtraRequest, T as Method, _ as RecordedMeta, a as MockWebsocketItem, b as RecordedRes, c as MockHttpItem, d as LogType, f as MockMatchPriority, g as RecordOptions, h as ServerBuildOption, i as MockOptions, j as SimpleHandleFunction, k as NextHandleFunction, l as BodyParserOptions, m as MockServerPluginOptions, n as HttpProxyPlugin, o as WebSocketSetupContext, p as MockMatchSpecialPriority, r as PathFilter, s as MockErrorConfig, t as FormidableFile, u as LogLevel, v as RecordedReq, w as Headers, x as ResolvedRecordOptions, y as RecordedRequest } from "./index-BMMGM-eD.js";
3
2
  import { IncomingMessage, OutgoingHttpHeaders, ServerResponse } from "node:http";
3
+ import { Transform } from "node:stream";
4
4
 
5
- //#region src/helper/createSSEStream.d.ts
5
+ //#region src/helpers/createSSEStream.d.ts
6
6
  interface SSEMessage {
7
7
  data?: string | object;
8
8
  comment?: string;
@@ -56,9 +56,9 @@ declare class SSEStream extends Transform {
56
56
  */
57
57
  declare function createSSEStream(req: IncomingMessage, res: ServerResponse): SSEStream;
58
58
  //#endregion
59
- //#region src/helper/defineMock.d.ts
59
+ //#region src/helpers/defineMock.d.ts
60
60
  /**
61
- * mock config Type helper
61
+ * Mock config Type helper
62
62
  *
63
63
  * mock配置 类型帮助函数
64
64
  * @param config see config docs:
@@ -117,10 +117,48 @@ declare function defineMock(config: MockOptions): MockOptions;
117
117
  */
118
118
  declare function createDefineMock(transformer: (mock: MockHttpItem | MockWebsocketItem) => MockHttpItem | MockWebsocketItem | void): typeof defineMock;
119
119
  //#endregion
120
- //#region src/helper/defineMockData.d.ts
120
+ //#region src/helpers/defineMockData.d.ts
121
+ /**
122
+ * Options for defineMockData
123
+ *
124
+ * defineMockData 的选项
125
+ */
126
+ interface DefineMockDataOptions {
127
+ /**
128
+ * Whether to persist the data value on HMR (Hot Module Replacement).
129
+ *
130
+ * 热更新时是否保持数据值
131
+ *
132
+ * @default false
133
+ */
134
+ persistOnHMR?: boolean;
135
+ }
136
+ /**
137
+ * Mock data type with getter, setter, and value property
138
+ *
139
+ * 带有 getter、setter 和 value 属性的 Mock 数据类型
140
+ *
141
+ * @template T - Type of mock data / Mock 数据的类型
142
+ */
121
143
  type MockData<T = any> = readonly [() => T, (val: T | ((val: T) => T | void)) => void] & {
144
+ /**
145
+ * Current value
146
+ *
147
+ * 当前值
148
+ */
122
149
  value: T;
123
150
  };
124
- declare function defineMockData<T = any>(key: string, initialData: T): MockData<T>;
151
+ /**
152
+ * Define mock data with memory-based sharing mechanism
153
+ *
154
+ * 定义带有基于内存的共享机制的 Mock 数据
155
+ *
156
+ * @template T - Type of mock data / Mock 数据的类型
157
+ * @param key - Unique key for mock data / Mock 数据的唯一键
158
+ * @param initialData - Initial data value / 初始数据值
159
+ * @param options - Options / 选项
160
+ * @returns MockData object with getter, setter, and value property / 带有 getter、setter 和 value 属性的 MockData 对象
161
+ */
162
+ declare function defineMockData<T = any>(key: string, initialData: T, options?: DefineMockDataOptions): MockData<T>;
125
163
  //#endregion
126
- export { BodyParserOptions, ExtraRequest, FormidableFile, HeaderStream, LogLevel, LogType, Method, MockData, MockHttpItem, MockMatchPriority, MockMatchSpecialPriority, MockOptions, MockRequest, MockResponse, MockServerPluginOptions, MockWebsocketItem, ResponseBody, SSEMessage, ServerBuildOption, WebSocketSetupContext, createDefineMock, createSSEStream, defineMock, defineMockData };
164
+ export { BodyParserOptions, CookiesOption, DefineMockDataOptions, ExtraRequest, FormidableFile, GetCookieOption, HandleFunction, HeaderStream, Headers, HttpProxyPlugin, LogLevel, LogType, Method, MockData, MockErrorConfig, MockHttpItem, MockMatchPriority, MockMatchSpecialPriority, MockOptions, MockRequest, MockResponse, MockServerPluginOptions, MockWebsocketItem, NextFunction, NextHandleFunction, PathFilter, RecordOptions, RecordedMeta, RecordedReq, RecordedRequest, RecordedRes, ResolvedRecordOptions, ResponseBody, SSEMessage, ServerBuildOption, SetCookieOption, SimpleHandleFunction, WebSocketSetupContext, createDefineMock, createSSEStream, defineMock, defineMockData };
package/dist/helper.js ADDED
@@ -0,0 +1,267 @@
1
+ import { deepClone, isArray, isFunction } from "@pengzhanbo/utils";
2
+ import { createHash } from "node:crypto";
3
+ import { Transform } from "node:stream";
4
+ //#region src/helpers/createSSEStream.ts
5
+ /**
6
+ * Transforms "messages" to W3C event stream content.
7
+ * See https://html.spec.whatwg.org/multipage/server-sent-events.html
8
+ * A message is an object with one or more of the following properties:
9
+ * - data (String or object, which gets turned into JSON)
10
+ * - event
11
+ * - id
12
+ * - retry
13
+ * - comment
14
+ *
15
+ * If constructed with a HTTP Request, it will optimise the socket for streaming.
16
+ * If this stream is piped to an HTTP Response, it will set appropriate headers.
17
+ */
18
+ var SSEStream = class extends Transform {
19
+ constructor(req) {
20
+ super({ objectMode: true });
21
+ req.socket.setKeepAlive(true);
22
+ req.socket.setNoDelay(true);
23
+ req.socket.setTimeout(0);
24
+ }
25
+ pipe(destination, options) {
26
+ if (destination.writeHead) {
27
+ destination.writeHead(200, {
28
+ "Content-Type": "text/event-stream; charset=utf-8",
29
+ "Transfer-Encoding": "identity",
30
+ "Cache-Control": "no-cache",
31
+ "Connection": "keep-alive"
32
+ });
33
+ destination.flushHeaders?.();
34
+ }
35
+ destination.write(":ok\n\n");
36
+ return super.pipe(destination, options);
37
+ }
38
+ _transform(message, encoding, callback) {
39
+ if (message.comment) this.push(`: ${message.comment}\n`);
40
+ if (message.event) this.push(`event: ${message.event}\n`);
41
+ if (message.id) this.push(`id: ${message.id}\n`);
42
+ if (message.retry) this.push(`retry: ${message.retry}\n`);
43
+ if (message.data) this.push(dataString(message.data));
44
+ this.push("\n");
45
+ callback();
46
+ }
47
+ write(message, ...args) {
48
+ return super.write(message, ...args);
49
+ }
50
+ destroy(error) {
51
+ if (error) this.write({
52
+ event: "error",
53
+ data: error.message
54
+ });
55
+ this.end();
56
+ return this;
57
+ }
58
+ };
59
+ function dataString(data) {
60
+ if (typeof data === "object") return dataString(JSON.stringify(data));
61
+ return data.split(/\r\n|\r|\n/).map((line) => `data: ${line}\n`).join("");
62
+ }
63
+ /**
64
+ * 创建一个 Server-sent events 写入流,用于支持模拟 EventSource
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * import { createSSEStream, defineMock } from 'vite-plugin-mock-dev-server'
69
+ *
70
+ * export default defineMock({
71
+ * url: '/api',
72
+ * response: (req, res) => {
73
+ * const sse = createSSEStream(req, res)
74
+ * sse.write({ event: 'message', data: { message: 'hello world' } })
75
+ * }
76
+ * })
77
+ * ```
78
+ */
79
+ function createSSEStream(req, res) {
80
+ const sse = new SSEStream(req);
81
+ sse.pipe(res);
82
+ return sse;
83
+ }
84
+ //#endregion
85
+ //#region src/helpers/defineMock.ts
86
+ function defineMock(config) {
87
+ return config;
88
+ }
89
+ /**
90
+ * Return a custom defineMock function to support preprocessing of mock config.
91
+ *
92
+ * 返回一个自定义的 defineMock 函数,用于支持对 mock config 的预处理。
93
+ * @param transformer preprocessing function
94
+ * @example
95
+ * ```ts
96
+ * const definePostMock = createDefineMock((mock) => {
97
+ * mock.url = '/api/post/' + mock.url
98
+ * })
99
+ * export default definePostMock({
100
+ * url: 'list',
101
+ * body: [{ title: '1' }, { title: '2' }],
102
+ * })
103
+ * ```
104
+ */
105
+ function createDefineMock(transformer) {
106
+ const define = (config) => {
107
+ if (isArray(config)) config = config.map((item) => transformer(item) || item);
108
+ else config = transformer(config) || config;
109
+ return config;
110
+ };
111
+ return define;
112
+ }
113
+ //#endregion
114
+ //#region src/helpers/defineMockData.ts
115
+ /**
116
+ * Since the plugin compiles `*.mock.*` files as separate independent entries,
117
+ * this leads to inconsistent dependency relationships after mock file compilation,
118
+ * with each mock file having its own scope.
119
+ * Even if multiple `*.mock.*` files import the same `data.ts` file, they are
120
+ * completely different instances of `data`, making operations on `data` not
121
+ * shareable across different `*.mock.*` files.
122
+ *
123
+ * To address this, the plugin provides a memory-based data sharing mechanism.
124
+ *
125
+ * 由于插件是分别独立对 `*.mock.*` 等文件作为单独入口进行编译的,
126
+ * 这导致了 mock 文件编译后的依赖关系不一致,每个 mock 文件拥有独立的作用域,
127
+ * 使得即使多个 `*.mock.*` 虽然引入了同一个 `data.ts` 文件,然而确是完全不同两份 `data`,
128
+ * 使得对 `data` 的操作,在不同的 `*.mock.*` 文件中并不能共享。
129
+ *
130
+ * 为此,插件提供了一种基于 memory 的数据共享机制。
131
+ */
132
+ /**
133
+ * Mock data cache
134
+ *
135
+ * Mock 数据缓存
136
+ */
137
+ const mockDataCache = /* @__PURE__ */ new Map();
138
+ /**
139
+ * Response cache for MockData objects
140
+ *
141
+ * MockData 对象的响应缓存
142
+ */
143
+ const responseCache = /* @__PURE__ */ new WeakMap();
144
+ /**
145
+ * Stale interval in milliseconds
146
+ *
147
+ * 缓存过期间隔(毫秒)
148
+ */
149
+ const staleInterval = 70;
150
+ /**
151
+ * Cache implementation for mock data
152
+ *
153
+ * Mock 数据缓存实现
154
+ *
155
+ * @template T - Type of cached data / 缓存数据的类型
156
+ */
157
+ var CacheImpl = class {
158
+ /**
159
+ * Current cached value
160
+ *
161
+ * 当前缓存值
162
+ */
163
+ value;
164
+ /**
165
+ * Initial value hash, used to detect if initial data has changed
166
+ *
167
+ * 初始化数据的哈希值,用于判断传入的初始化数据是否发生变更
168
+ */
169
+ #hash;
170
+ /**
171
+ * Last update timestamp
172
+ *
173
+ * 最后更新时间戳
174
+ */
175
+ #lastUpdate;
176
+ /**
177
+ * Whether to persist data on HMR
178
+ *
179
+ * 热更新时是否保持数据
180
+ */
181
+ #persistOnHMR;
182
+ /**
183
+ * Constructor
184
+ *
185
+ * 构造函数
186
+ *
187
+ * @param value - Initial value / 初始值
188
+ * @param persistOnHMR - Whether to persist data on HMR / 热更新时是否保持数据
189
+ */
190
+ constructor(value, persistOnHMR) {
191
+ this.value = value;
192
+ this.#hash = getHash(value);
193
+ this.#lastUpdate = Date.now();
194
+ this.#persistOnHMR = persistOnHMR ?? false;
195
+ }
196
+ /**
197
+ * Hot update cached value
198
+ *
199
+ * 热更新缓存值
200
+ *
201
+ * @param value - New value / 新值
202
+ */
203
+ hotUpdate(value) {
204
+ if (this.#persistOnHMR) return;
205
+ if (Date.now() - this.#lastUpdate < staleInterval) return;
206
+ const hash = getHash(value);
207
+ if (this.#hash !== hash) {
208
+ this.value = deepClone(value);
209
+ this.#hash = hash;
210
+ this.#lastUpdate = Date.now();
211
+ }
212
+ }
213
+ /**
214
+ * Set persistOnHMR
215
+ *
216
+ * 设置 persistOnHMR
217
+ *
218
+ * @param persistOnHMR - Whether to persist data on HMR / 热更新时是否保持数据
219
+ */
220
+ setPersistOnHMR(persistOnHMR) {
221
+ if (!this.#persistOnHMR) this.#persistOnHMR = persistOnHMR;
222
+ }
223
+ };
224
+ /**
225
+ * Define mock data with memory-based sharing mechanism
226
+ *
227
+ * 定义带有基于内存的共享机制的 Mock 数据
228
+ *
229
+ * @template T - Type of mock data / Mock 数据的类型
230
+ * @param key - Unique key for mock data / Mock 数据的唯一键
231
+ * @param initialData - Initial data value / 初始数据值
232
+ * @param options - Options / 选项
233
+ * @returns MockData object with getter, setter, and value property / 带有 getter、setter 和 value 属性的 MockData 对象
234
+ */
235
+ function defineMockData(key, initialData, options) {
236
+ let cache = mockDataCache.get(key);
237
+ if (!cache) {
238
+ const newCache = new CacheImpl(initialData, options?.persistOnHMR);
239
+ const existing = mockDataCache.get(key);
240
+ if (existing) cache = existing;
241
+ else {
242
+ mockDataCache.set(key, newCache);
243
+ cache = newCache;
244
+ }
245
+ } else cache.setPersistOnHMR(options?.persistOnHMR ?? false);
246
+ cache.hotUpdate(initialData);
247
+ if (responseCache.has(cache)) return responseCache.get(cache);
248
+ const res = [() => cache.value, (val) => {
249
+ if (isFunction(val)) val = val(cache.value) ?? cache.value;
250
+ cache.value = val;
251
+ }];
252
+ Object.defineProperty(res, "value", {
253
+ get() {
254
+ return cache.value;
255
+ },
256
+ set(val) {
257
+ cache.value = val;
258
+ }
259
+ });
260
+ responseCache.set(cache, res);
261
+ return res;
262
+ }
263
+ function getHash(data) {
264
+ return createHash("sha256").update(JSON.stringify(data)).digest("hex");
265
+ }
266
+ //#endregion
267
+ export { createDefineMock, createSSEStream, defineMock, defineMockData };