rspack-plugin-mock 0.2.0 → 0.3.1

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,72 +1,3 @@
1
- // src/core/utils.ts
2
- import fs from "fs";
3
- import path from "path";
4
- import { parse as queryParse } from "querystring";
5
- import { URL as URL2, fileURLToPath } from "url";
6
- import os from "os";
7
- import Debug from "debug";
8
- import { match } from "path-to-regexp";
9
- function isStream(stream) {
10
- return stream !== null && typeof stream === "object" && typeof stream.pipe === "function";
11
- }
12
- function isReadableStream(stream) {
13
- return isStream(stream) && stream.readable !== false && typeof stream._read === "function" && typeof stream._readableState === "object";
14
- }
15
- function getDirname(importMetaUrl) {
16
- return path.dirname(fileURLToPath(importMetaUrl));
17
- }
18
- var debug = Debug("rspack:mock");
19
- function lookupFile(dir, formats, options) {
20
- for (const format of formats) {
21
- const fullPath = path.join(dir, format);
22
- if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
23
- const result = options?.pathOnly ? fullPath : fs.readFileSync(fullPath, "utf-8");
24
- if (!options?.predicate || options.predicate(result))
25
- return result;
26
- }
27
- }
28
- const parentDir = path.dirname(dir);
29
- if (parentDir !== dir && (!options?.rootDir || parentDir.startsWith(options?.rootDir))) {
30
- return lookupFile(parentDir, formats, options);
31
- }
32
- }
33
- function doesProxyContextMatchUrl(context, url, req) {
34
- if (typeof context === "function") {
35
- return context(url, req);
36
- }
37
- return context[0] === "^" && new RegExp(context).test(url) || url.startsWith(context);
38
- }
39
- function parseParams(pattern, url) {
40
- const urlMatch = match(pattern, { decode: decodeURIComponent })(url) || {
41
- params: {}
42
- };
43
- return urlMatch.params || {};
44
- }
45
- function urlParse(input) {
46
- const url = new URL2(input, "http://example.com");
47
- const pathname = decodeURIComponent(url.pathname);
48
- const query = queryParse(url.search.replace(/^\?/, ""));
49
- return { pathname, query };
50
- }
51
- var windowsSlashRE = /\\/g;
52
- var isWindows = os.platform() === "win32";
53
- function slash(p) {
54
- return p.replace(windowsSlashRE, "/");
55
- }
56
- function normalizePath(id) {
57
- return path.posix.normalize(isWindows ? slash(id) : id);
58
- }
59
- function waitingFor(onSuccess, maxRetry = 5) {
60
- return function wait(getter, retry = 0) {
61
- const value = getter();
62
- if (value) {
63
- onSuccess(value);
64
- } else if (retry < maxRetry) {
65
- setTimeout(() => wait(getter, retry + 1), 100);
66
- }
67
- };
68
- }
69
-
70
1
  // src/core/requestRecovery.ts
71
2
  import { Buffer } from "buffer";
72
3
  var requestCollectCache = /* @__PURE__ */ new WeakMap();
@@ -91,10 +22,6 @@ function rewriteRequest(proxyReq, req) {
91
22
  }
92
23
  }
93
24
 
94
- // src/core/mockMiddleware.ts
95
- import cors from "cors";
96
- import { pathToRegexp as pathToRegexp3 } from "path-to-regexp";
97
-
98
25
  // src/core/baseMiddleware.ts
99
26
  import { Buffer as Buffer2 } from "buffer";
100
27
  import {
@@ -238,7 +165,7 @@ function matchingWeight(rules, url, priority) {
238
165
  const options = special[specialRule];
239
166
  const { rules: lowerRules, when } = isArray(options) ? { rules: options, when: [] } : options;
240
167
  if (lowerRules.includes(matched[0])) {
241
- if (when.length === 0 || when.some((path5) => pathToRegexp(path5).test(url))) {
168
+ if (when.length === 0 || when.some((path2) => pathToRegexp(path2).test(url))) {
242
169
  matched = uniq([specialRule, ...matched]);
243
170
  }
244
171
  }
@@ -305,6 +232,78 @@ async function parseMultipart(req, options) {
305
232
  });
306
233
  }
307
234
 
235
+ // src/core/utils.ts
236
+ import fs from "fs";
237
+ import path from "path";
238
+ import { parse as queryParse } from "querystring";
239
+ import { URL as URL2, fileURLToPath } from "url";
240
+ import os from "os";
241
+ import Debug from "debug";
242
+ import { match } from "path-to-regexp";
243
+ import { Volume, createFsFromVolume } from "memfs";
244
+ var packageDir = getDirname(import.meta.url);
245
+ var vfs = createFsFromVolume(new Volume());
246
+ function isStream(stream) {
247
+ return stream !== null && typeof stream === "object" && typeof stream.pipe === "function";
248
+ }
249
+ function isReadableStream(stream) {
250
+ return isStream(stream) && stream.readable !== false && typeof stream._read === "function" && typeof stream._readableState === "object";
251
+ }
252
+ function getDirname(importMetaUrl) {
253
+ return path.dirname(fileURLToPath(importMetaUrl));
254
+ }
255
+ var debug = Debug("rspack:mock");
256
+ function lookupFile(dir, formats, options) {
257
+ for (const format of formats) {
258
+ const fullPath = path.join(dir, format);
259
+ if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
260
+ const result = options?.pathOnly ? fullPath : fs.readFileSync(fullPath, "utf-8");
261
+ if (!options?.predicate || options.predicate(result))
262
+ return result;
263
+ }
264
+ }
265
+ const parentDir = path.dirname(dir);
266
+ if (parentDir !== dir && (!options?.rootDir || parentDir.startsWith(options?.rootDir))) {
267
+ return lookupFile(parentDir, formats, options);
268
+ }
269
+ }
270
+ function doesProxyContextMatchUrl(context, url, req) {
271
+ if (typeof context === "function") {
272
+ return context(url, req);
273
+ }
274
+ return context[0] === "^" && new RegExp(context).test(url) || url.startsWith(context);
275
+ }
276
+ function parseParams(pattern, url) {
277
+ const urlMatch = match(pattern, { decode: decodeURIComponent })(url) || {
278
+ params: {}
279
+ };
280
+ return urlMatch.params || {};
281
+ }
282
+ function urlParse(input) {
283
+ const url = new URL2(input, "http://example.com");
284
+ const pathname = decodeURIComponent(url.pathname);
285
+ const query = queryParse(url.search.replace(/^\?/, ""));
286
+ return { pathname, query };
287
+ }
288
+ var windowsSlashRE = /\\/g;
289
+ var isWindows = os.platform() === "win32";
290
+ function slash(p) {
291
+ return p.replace(windowsSlashRE, "/");
292
+ }
293
+ function normalizePath(id) {
294
+ return path.posix.normalize(isWindows ? slash(id) : id);
295
+ }
296
+ function waitingFor(onSuccess, maxRetry = 5) {
297
+ return function wait(getter, retry = 0) {
298
+ const value = getter();
299
+ if (value) {
300
+ onSuccess(value);
301
+ } else if (retry < maxRetry) {
302
+ setTimeout(() => wait(getter, retry + 1), 100);
303
+ }
304
+ };
305
+ }
306
+
308
307
  // src/core/validator.ts
309
308
  import { isArray as isArray2, isObject } from "@pengzhanbo/utils";
310
309
  function validate(request, validator) {
@@ -601,52 +600,6 @@ function requestLog(request, filepath) {
601
600
  return `${ms} ${pathname}${qs}${ps}${bs}${file}`;
602
601
  }
603
602
 
604
- // src/core/mockMiddleware.ts
605
- function createMockMiddleware(compiler, options) {
606
- function mockMiddleware(middlewares, reload) {
607
- middlewares.unshift(baseMiddleware(compiler, options));
608
- const corsMiddleware = createCorsMiddleware(compiler, options);
609
- if (corsMiddleware) {
610
- middlewares.unshift(corsMiddleware);
611
- }
612
- if (options.reload) {
613
- compiler.on("update", () => reload?.());
614
- }
615
- return middlewares;
616
- }
617
- return mockMiddleware;
618
- }
619
- function createCorsMiddleware(compiler, options) {
620
- let corsOptions = {};
621
- const enabled = options.cors !== false;
622
- if (enabled) {
623
- corsOptions = {
624
- ...corsOptions,
625
- ...typeof options.cors === "boolean" ? {} : options.cors
626
- };
627
- }
628
- const proxies = options.proxies;
629
- return !enabled ? void 0 : function(req, res, next) {
630
- const { pathname } = urlParse(req.url);
631
- if (!pathname || proxies.length === 0 || !proxies.some(
632
- (context) => doesProxyContextMatchUrl(context, req.url, req)
633
- )) {
634
- return next();
635
- }
636
- const mockData = compiler.mockData;
637
- const mockUrl = Object.keys(mockData).find(
638
- (key) => pathToRegexp3(key).test(pathname)
639
- );
640
- if (!mockUrl)
641
- return next();
642
- cors(corsOptions)(req, res, next);
643
- };
644
- }
645
-
646
- // src/core/resolvePluginOptions.ts
647
- import process from "process";
648
- import { isBoolean as isBoolean2, toArray } from "@pengzhanbo/utils";
649
-
650
603
  // src/core/logger.ts
651
604
  import { isBoolean } from "@pengzhanbo/utils";
652
605
  import colors2 from "picocolors";
@@ -688,103 +641,13 @@ function createLogger(prefix, defaultLevel = "info") {
688
641
  return logger;
689
642
  }
690
643
 
691
- // src/core/resolvePluginOptions.ts
692
- function resolvePluginOptions({
693
- prefix = [],
694
- wsPrefix = [],
695
- cwd,
696
- include = ["mock/**/*.mock.{js,ts,cjs,mjs,json,json5}"],
697
- exclude = ["**/node_modules/**", "**/.vscode/**", "**/.git/**"],
698
- reload = false,
699
- log = "info",
700
- cors: cors2 = true,
701
- formidableOptions = {},
702
- build = false,
703
- cookiesOptions = {},
704
- bodyParserOptions = {},
705
- priority = {}
706
- } = {}, { alias, context, plugins, proxies }) {
707
- const logger = createLogger(
708
- "rspack:mock",
709
- isBoolean2(log) ? log ? "info" : "error" : log
710
- );
711
- return {
712
- prefix,
713
- wsPrefix,
714
- cwd: cwd || context || process.cwd(),
715
- include,
716
- exclude,
717
- reload,
718
- cors: cors2,
719
- cookiesOptions,
720
- log,
721
- formidableOptions: {
722
- multiples: true,
723
- ...formidableOptions
724
- },
725
- bodyParserOptions,
726
- priority,
727
- build: build ? Object.assign(
728
- {
729
- serverPort: 8080,
730
- dist: "mockServer",
731
- log: "error"
732
- },
733
- typeof build === "object" ? build : {}
734
- ) : false,
735
- alias,
736
- plugins,
737
- proxies,
738
- wsProxies: toArray(wsPrefix),
739
- logger
740
- };
741
- }
742
-
743
- // src/core/mockCompiler.ts
744
- import EventEmitter from "events";
745
- import fs3, { promises as fsp2 } from "fs";
746
- import process2 from "process";
747
- import path4 from "path";
748
- import fastGlob from "fast-glob";
749
- import chokidar from "chokidar";
750
- import { createFilter } from "@rollup/pluginutils";
751
- import * as rspackCore from "@rspack/core";
752
- import { Volume, createFsFromVolume } from "memfs";
753
- import { toArray as toArray3 } from "@pengzhanbo/utils";
754
- import color from "picocolors";
755
-
756
- // src/core/loadFromCode.ts
757
- import path2 from "path";
758
- import fs2, { promises as fsp } from "fs";
759
- async function loadFromCode({
760
- filepath,
761
- code,
762
- isESM,
763
- cwd
764
- }) {
765
- filepath = path2.resolve(cwd, filepath);
766
- const fileBase = `${filepath}.timestamp-${Date.now()}`;
767
- const ext = isESM ? ".mjs" : ".cjs";
768
- const fileNameTmp = `${fileBase}${ext}`;
769
- await fsp.writeFile(fileNameTmp, code, "utf8");
770
- try {
771
- const result = await import(fileNameTmp);
772
- return result.default || result;
773
- } finally {
774
- try {
775
- fs2.unlinkSync(fileNameTmp);
776
- } catch {
777
- }
778
- }
779
- }
780
-
781
644
  // src/core/transform.ts
782
645
  import {
783
646
  isEmptyObject as isEmptyObject3,
784
647
  isFunction as isFunction2,
785
648
  isObject as isObject2,
786
649
  sortBy as sortBy2,
787
- toArray as toArray2
650
+ toArray
788
651
  } from "@pengzhanbo/utils";
789
652
  function transformRawData(rawData) {
790
653
  return rawData.filter((item) => item[0]).map(([raw, __filepath__]) => {
@@ -814,7 +677,7 @@ function transformMockData(mockList) {
814
677
  const list = [];
815
678
  for (const [, handle] of mockList.entries()) {
816
679
  if (handle)
817
- list.push(...toArray2(handle));
680
+ list.push(...toArray(handle));
818
681
  }
819
682
  const mocks = {};
820
683
  list.filter((mock) => isObject2(mock) && mock.enabled !== false && mock.url).forEach((mock) => {
@@ -865,224 +728,9 @@ function keysCount(obj) {
865
728
  return Object.keys(obj).length;
866
729
  }
867
730
 
868
- // src/core/resolveRspackOptions.ts
869
- import path3 from "path";
870
- var _dirname = getDirname(import.meta.url);
871
- function resolveRspackOptions({
872
- cwd,
873
- isEsm,
874
- entryFile,
875
- outputFile,
876
- plugins,
877
- alias,
878
- watch = false
879
- }) {
880
- const targets = ["node >= 18.0.0"];
881
- return {
882
- mode: "production",
883
- context: cwd,
884
- entry: entryFile,
885
- watch,
886
- target: "node18.0",
887
- externalsType: isEsm ? "module" : "commonjs2",
888
- externals: /^[^./].*/,
889
- resolve: {
890
- alias,
891
- extensions: [".js", ".ts", ".cjs", ".mjs", ".json5", ".json"]
892
- },
893
- plugins,
894
- output: {
895
- library: { type: !isEsm ? "commonjs2" : "module" },
896
- filename: outputFile,
897
- path: "/"
898
- },
899
- experiments: { outputModule: isEsm },
900
- module: {
901
- rules: [
902
- {
903
- test: /\.json5?$/,
904
- loader: path3.join(_dirname, "json5-loader.cjs"),
905
- type: "javascript/auto"
906
- },
907
- {
908
- test: /\.[cm]?js$/,
909
- use: [
910
- {
911
- loader: "builtin:swc-loader",
912
- options: {
913
- jsc: { parser: { syntax: "ecmascript" } },
914
- env: { targets }
915
- }
916
- }
917
- ]
918
- },
919
- {
920
- test: /\.[cm]?ts$/,
921
- use: [
922
- {
923
- loader: "builtin:swc-loader",
924
- options: {
925
- jsc: { parser: { syntax: "typescript" } },
926
- env: { targets }
927
- }
928
- }
929
- ]
930
- }
931
- ]
932
- }
933
- };
934
- }
935
-
936
- // src/core/mockCompiler.ts
937
- var vfs = createFsFromVolume(new Volume());
938
- function createMockCompiler(options) {
939
- return new MockCompiler(options);
940
- }
941
- var MockCompiler = class extends EventEmitter {
942
- constructor(options) {
943
- super();
944
- this.options = options;
945
- this.cwd = options.cwd || process2.cwd();
946
- const { include, exclude } = this.options;
947
- this.fileFilter = createFilter(include, exclude, { resolve: false });
948
- try {
949
- const pkg = lookupFile(this.cwd, ["package.json"]);
950
- this.moduleType = !!pkg && JSON.parse(pkg).type === "module" ? "esm" : "cjs";
951
- } catch {
952
- }
953
- this.entryFile = path4.resolve(process2.cwd(), "node_modules/.cache/mock-server/mock-server.ts");
954
- this.outputFile = "mock.bundle.js";
955
- }
956
- cwd;
957
- mockWatcher;
958
- moduleType = "cjs";
959
- entryFile;
960
- outputFile;
961
- _mockData = {};
962
- fileFilter;
963
- watchInfo;
964
- compiler;
965
- get mockData() {
966
- return this._mockData;
967
- }
968
- async run() {
969
- await this.updateMockEntry();
970
- this.watchMockFiles();
971
- this.createCompiler(async (err, stats) => {
972
- const name = "[rspack:mock]";
973
- const logError = stats?.compilation.getLogger(name).error || ((...args) => console.error(color.red(name), ...args));
974
- if (err) {
975
- logError(err.stack || err);
976
- if ("details" in err) {
977
- logError(err.details);
978
- }
979
- return;
980
- }
981
- if (stats?.hasErrors()) {
982
- const info = stats.toJson();
983
- logError(info.errors);
984
- return;
985
- }
986
- const content = vfs.readFileSync(`/${this.outputFile}`, "utf-8");
987
- try {
988
- const result = await loadFromCode({
989
- filepath: this.outputFile,
990
- code: content,
991
- isESM: this.moduleType === "esm",
992
- cwd: this.cwd
993
- });
994
- this._mockData = transformMockData(transformRawData(result));
995
- this.emit("update", this.watchInfo || {});
996
- } catch (e) {
997
- logError(e);
998
- }
999
- });
1000
- }
1001
- close() {
1002
- this.mockWatcher.close();
1003
- this.compiler?.close(() => {
1004
- });
1005
- this.emit("close");
1006
- }
1007
- updateAlias(alias) {
1008
- this.options.alias = {
1009
- ...this.options.alias,
1010
- ...alias
1011
- };
1012
- }
1013
- async updateMockEntry() {
1014
- const files = await this.getMockFiles();
1015
- await this.resolveEntryFile(files);
1016
- }
1017
- async getMockFiles() {
1018
- const { include } = this.options;
1019
- const files = await fastGlob(include, { cwd: this.cwd });
1020
- return files.filter(this.fileFilter);
1021
- }
1022
- watchMockFiles() {
1023
- const { include } = this.options;
1024
- const [firstGlob, ...otherGlob] = toArray3(include);
1025
- const watcher = this.mockWatcher = chokidar.watch(firstGlob, {
1026
- ignoreInitial: true,
1027
- cwd: this.cwd
1028
- });
1029
- if (otherGlob.length > 0)
1030
- otherGlob.forEach((glob) => watcher.add(glob));
1031
- watcher.on("add", (filepath) => {
1032
- if (this.fileFilter(filepath)) {
1033
- this.watchInfo = { filepath, type: "add" };
1034
- this.updateMockEntry();
1035
- }
1036
- });
1037
- watcher.on("change", (filepath) => {
1038
- if (this.fileFilter(filepath)) {
1039
- this.watchInfo = { filepath, type: "change" };
1040
- }
1041
- });
1042
- watcher.on("unlink", async (filepath) => {
1043
- this.watchInfo = { filepath, type: "unlink" };
1044
- this.updateMockEntry();
1045
- });
1046
- }
1047
- async resolveEntryFile(fileList) {
1048
- const importers = [];
1049
- const exporters = [];
1050
- for (const [index, filepath] of fileList.entries()) {
1051
- const file = normalizePath(path4.join(this.cwd, filepath));
1052
- importers.push(`import * as m${index} from '${file}'`);
1053
- exporters.push(`[m${index}, '${filepath}']`);
1054
- }
1055
- const code = `${importers.join("\n")}
1056
-
1057
- export default [
1058
- ${exporters.join(",\n ")}
1059
- ]`;
1060
- const dirname = path4.dirname(this.entryFile);
1061
- if (!fs3.existsSync(dirname)) {
1062
- await fsp2.mkdir(dirname, { recursive: true });
1063
- }
1064
- await fsp2.writeFile(this.entryFile, code, "utf8");
1065
- }
1066
- createCompiler(callback) {
1067
- const { plugins, alias } = this.options;
1068
- const options = resolveRspackOptions({
1069
- isEsm: this.moduleType === "esm",
1070
- cwd: this.cwd,
1071
- plugins,
1072
- entryFile: this.entryFile,
1073
- outputFile: this.outputFile,
1074
- alias,
1075
- watch: true
1076
- });
1077
- this.compiler = rspackCore.rspack(options, callback);
1078
- if (this.compiler)
1079
- this.compiler.outputFileSystem = vfs;
1080
- }
1081
- };
1082
-
1083
731
  // src/core/mockWebsocket.ts
1084
732
  import Cookies2 from "cookies";
1085
- import { pathToRegexp as pathToRegexp4 } from "path-to-regexp";
733
+ import { pathToRegexp as pathToRegexp3 } from "path-to-regexp";
1086
734
  import colors3 from "picocolors";
1087
735
  import { WebSocketServer } from "ws";
1088
736
  function mockWebSocket(compiler, httpServer, {
@@ -1177,12 +825,12 @@ ${e}
1177
825
  }
1178
826
  const mockData = compiler.mockData;
1179
827
  const mockUrl = Object.keys(mockData).find((key) => {
1180
- return pathToRegexp4(key).test(pathname);
828
+ return pathToRegexp3(key).test(pathname);
1181
829
  });
1182
830
  if (!mockUrl)
1183
831
  return;
1184
832
  const mock = mockData[mockUrl].find((mock2) => {
1185
- return mock2.url && mock2.ws && pathToRegexp4(mock2.url).test(pathname);
833
+ return mock2.url && mock2.ws && pathToRegexp3(mock2.url).test(pathname);
1186
834
  });
1187
835
  if (!mock)
1188
836
  return;
@@ -1238,10 +886,19 @@ function cleanupRunner(cleanupList) {
1238
886
  }
1239
887
 
1240
888
  export {
889
+ packageDir,
890
+ vfs,
891
+ lookupFile,
892
+ doesProxyContextMatchUrl,
893
+ urlParse,
894
+ normalizePath,
1241
895
  waitingFor,
1242
896
  rewriteRequest,
1243
- createMockMiddleware,
1244
- resolvePluginOptions,
1245
- createMockCompiler,
897
+ baseMiddleware,
898
+ logLevels,
899
+ createLogger,
900
+ transformRawData,
901
+ transformMockData,
902
+ sortByValidator,
1246
903
  mockWebSocket
1247
904
  };