提交学习笔记专用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

66 lines
2.6 KiB

  1. import { isAbsolute, join, resolve } from "pathe";
  2. import pm from "picomatch";
  3. //#region src/path.ts
  4. /**
  5. * Converts path separators to forward slash.
  6. */
  7. function normalizePath(filename) {
  8. return filename.replaceAll("\\", "/");
  9. }
  10. //#endregion
  11. //#region src/utils.ts
  12. const isArray = Array.isArray;
  13. function toArray(thing) {
  14. if (isArray(thing)) return thing;
  15. if (thing == null) return [];
  16. return [thing];
  17. }
  18. //#endregion
  19. //#region src/filter.ts
  20. const escapeMark = "[_#EsCaPe#_]";
  21. function getMatcherString(id, resolutionBase) {
  22. if (resolutionBase === false || isAbsolute(id) || id.startsWith("**")) return normalizePath(id);
  23. const basePath = normalizePath(resolve(resolutionBase || "")).replaceAll(/[-^$*+?.()|[\]{}]/g, `${escapeMark}$&`);
  24. return join(basePath, normalizePath(id)).replaceAll(escapeMark, "\\");
  25. }
  26. /**
  27. * Constructs a filter function which can be used to determine whether or not
  28. * certain modules should be operated upon.
  29. * @param include If `include` is omitted or has zero length, filter will return `true` by default.
  30. * @param exclude ID must not match any of the `exclude` patterns.
  31. * @param options Additional options.
  32. * @param options.resolve Optionally resolves the patterns against a directory other than `process.cwd()`.
  33. * If a `string` is specified, then the value will be used as the base directory.
  34. * Relative paths will be resolved against `process.cwd()` first.
  35. * If `false`, then the patterns will not be resolved against any directory.
  36. * This can be useful if you want to create a filter for virtual module names.
  37. */
  38. function createFilter(include, exclude, options) {
  39. const resolutionBase = options && options.resolve;
  40. const getMatcher = (id) => id instanceof RegExp ? id : { test: (what) => {
  41. const pattern = getMatcherString(id, resolutionBase);
  42. return pm(pattern, { dot: true })(what);
  43. } };
  44. const includeMatchers = toArray(include).map(getMatcher);
  45. const excludeMatchers = toArray(exclude).map(getMatcher);
  46. if (!includeMatchers.length && !excludeMatchers.length) return (id) => typeof id === "string" && !id.includes("\0");
  47. return function result(id) {
  48. if (typeof id !== "string") return false;
  49. if (id.includes("\0")) return false;
  50. const pathId = normalizePath(id);
  51. for (const matcher of excludeMatchers) {
  52. if (matcher instanceof RegExp) matcher.lastIndex = 0;
  53. if (matcher.test(pathId)) return false;
  54. }
  55. for (const matcher of includeMatchers) {
  56. if (matcher instanceof RegExp) matcher.lastIndex = 0;
  57. if (matcher.test(pathId)) return true;
  58. }
  59. return !includeMatchers.length;
  60. };
  61. }
  62. //#endregion
  63. export { createFilter, normalizePath, toArray };