UNPKG

5.78 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright Google LLC All Rights Reserved.
5 *
6 * Use of this source code is governed by an MIT-style license that can be
7 * found in the LICENSE file at https://angular.io/license
8 */
9Object.defineProperty(exports, "__esModule", { value: true });
10exports.TypeScriptPathsPlugin = void 0;
11const path = require("path");
12const getInnerRequest = require('enhanced-resolve/lib/getInnerRequest');
13class TypeScriptPathsPlugin {
14 constructor(options) {
15 this.options = options;
16 }
17 update(options) {
18 this.options = options;
19 }
20 // eslint-disable-next-line @typescript-eslint/no-explicit-any
21 apply(resolver) {
22 const target = resolver.ensureHook('resolve');
23 const resolveAsync = (request, requestContext) => {
24 return new Promise((resolve, reject) => {
25 resolver.doResolve(target, request, '', requestContext, (error, result) => {
26 if (error) {
27 reject(error);
28 }
29 else {
30 resolve(result);
31 }
32 });
33 });
34 };
35 resolver
36 .getHook('described-resolve')
37 .tapPromise('TypeScriptPathsPlugin', async (request, resolveContext) => {
38 if (!this.options) {
39 throw new Error('TypeScriptPathsPlugin options were not provided.');
40 }
41 if (!request || request.typescriptPathMapped) {
42 return;
43 }
44 const originalRequest = getInnerRequest(resolver, request);
45 if (!originalRequest) {
46 return;
47 }
48 // Only work on Javascript/TypeScript issuers.
49 if (!request.context.issuer || !request.context.issuer.match(/\.[jt]sx?$/)) {
50 return;
51 }
52 // Relative or absolute requests are not mapped
53 if (originalRequest.startsWith('.') || originalRequest.startsWith('/')) {
54 return;
55 }
56 // Ignore all webpack special requests
57 if (originalRequest.startsWith('!!')) {
58 return;
59 }
60 const replacements = findReplacements(originalRequest, this.options.paths || {});
61 for (const potential of replacements) {
62 const potentialRequest = {
63 ...request,
64 request: path.resolve(this.options.baseUrl || '', potential),
65 typescriptPathMapped: true,
66 };
67 const result = await resolveAsync(potentialRequest, resolveContext);
68 if (result) {
69 return result;
70 }
71 }
72 });
73 }
74}
75exports.TypeScriptPathsPlugin = TypeScriptPathsPlugin;
76function findReplacements(originalRequest, paths) {
77 // check if any path mapping rules are relevant
78 const pathMapOptions = [];
79 for (const pattern in paths) {
80 // get potentials and remove duplicates; JS Set maintains insertion order
81 const potentials = Array.from(new Set(paths[pattern]));
82 if (potentials.length === 0) {
83 // no potential replacements so skip
84 continue;
85 }
86 // can only contain zero or one
87 const starIndex = pattern.indexOf('*');
88 if (starIndex === -1) {
89 if (pattern === originalRequest) {
90 pathMapOptions.push({
91 starIndex,
92 partial: '',
93 potentials,
94 });
95 }
96 }
97 else if (starIndex === 0 && pattern.length === 1) {
98 if (potentials.length === 1 && potentials[0] === '*') {
99 // identity mapping -> noop
100 continue;
101 }
102 pathMapOptions.push({
103 starIndex,
104 partial: originalRequest,
105 potentials,
106 });
107 }
108 else if (starIndex === pattern.length - 1) {
109 if (originalRequest.startsWith(pattern.slice(0, -1))) {
110 pathMapOptions.push({
111 starIndex,
112 partial: originalRequest.slice(pattern.length - 1),
113 potentials,
114 });
115 }
116 }
117 else {
118 const [prefix, suffix] = pattern.split('*');
119 if (originalRequest.startsWith(prefix) && originalRequest.endsWith(suffix)) {
120 pathMapOptions.push({
121 starIndex,
122 partial: originalRequest.slice(prefix.length).slice(0, -suffix.length),
123 potentials,
124 });
125 }
126 }
127 }
128 if (pathMapOptions.length === 0) {
129 return [];
130 }
131 // exact matches take priority then largest prefix match
132 pathMapOptions.sort((a, b) => {
133 if (a.starIndex === -1) {
134 return -1;
135 }
136 else if (b.starIndex === -1) {
137 return 1;
138 }
139 else {
140 return b.starIndex - a.starIndex;
141 }
142 });
143 const replacements = [];
144 pathMapOptions.forEach((option) => {
145 for (const potential of option.potentials) {
146 let replacement;
147 const starIndex = potential.indexOf('*');
148 if (starIndex === -1) {
149 replacement = potential;
150 }
151 else if (starIndex === potential.length - 1) {
152 replacement = potential.slice(0, -1) + option.partial;
153 }
154 else {
155 const [prefix, suffix] = potential.split('*');
156 replacement = prefix + option.partial + suffix;
157 }
158 replacements.push(replacement);
159 }
160 });
161 return replacements;
162}