mapping-entry.ts 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import * as path from "path";
  2. export interface MappingEntry {
  3. readonly pattern: string;
  4. readonly paths: ReadonlyArray<string>;
  5. }
  6. export interface Paths {
  7. readonly [key: string]: ReadonlyArray<string>;
  8. }
  9. /**
  10. * Converts an absolute baseUrl and paths to an array of absolute mapping entries.
  11. * The array is sorted by longest prefix.
  12. * Having an array with entries allows us to keep a sorting order rather than
  13. * sort by keys each time we use the mappings.
  14. * @param absoluteBaseUrl
  15. * @param paths
  16. * @param addMatchAll
  17. */
  18. export function getAbsoluteMappingEntries(
  19. absoluteBaseUrl: string,
  20. paths: Paths,
  21. addMatchAll: boolean
  22. ): ReadonlyArray<MappingEntry> {
  23. // Resolve all paths to absolute form once here, and sort them by
  24. // longest prefix once here, this saves time on each request later.
  25. // We need to put them in an array to preserve the sorting order.
  26. const sortedKeys = sortByLongestPrefix(Object.keys(paths));
  27. const absolutePaths: Array<MappingEntry> = [];
  28. for (const key of sortedKeys) {
  29. absolutePaths.push({
  30. pattern: key,
  31. paths: paths[key].map((pathToResolve) =>
  32. path.join(absoluteBaseUrl, pathToResolve)
  33. ),
  34. });
  35. }
  36. // If there is no match-all path specified in the paths section of tsconfig, then try to match
  37. // all paths relative to baseUrl, this is how typescript works.
  38. if (!paths["*"] && addMatchAll) {
  39. absolutePaths.push({
  40. pattern: "*",
  41. paths: [`${absoluteBaseUrl.replace(/\/$/, "")}/*`],
  42. });
  43. }
  44. return absolutePaths;
  45. }
  46. /**
  47. * Sort path patterns.
  48. * If a module name can be matched with multiple patterns then pattern with the longest prefix will be picked.
  49. */
  50. function sortByLongestPrefix(arr: Array<string>): Array<string> {
  51. return arr
  52. .concat()
  53. .sort((a: string, b: string) => getPrefixLength(b) - getPrefixLength(a));
  54. }
  55. function getPrefixLength(pattern: string): number {
  56. const prefixLength = pattern.indexOf("*");
  57. return pattern.substr(0, prefixLength).length;
  58. }