UNPKG

5.2 kBPlain TextView Raw
1import { setupTs, readConfigFile } from './instance';
2import { LoaderConfig } from './interfaces';
3import * as path from 'path';
4import * as _ from 'lodash';
5import * as ts from 'typescript';
6
7const ModulesInRootPlugin: new (a: string, b: string, c: string) => ResolverPlugin
8 = require('enhanced-resolve/lib/ModulesInRootPlugin');
9
10const createInnerCallback: CreateInnerCallback = require('enhanced-resolve/lib/createInnerCallback');
11const getInnerRequest: getInnerRequest = require('enhanced-resolve/lib/getInnerRequest');
12
13type CreateInnerCallback = (callback: Callback, options: Callback, message?: string, messageOptional?: string) => Callback;
14type getInnerRequest = (resolver: Resolver, request: Request) => string;
15
16export interface Request {
17 request?: Request;
18 relativePath: string;
19}
20
21export interface Callback {
22 (err?: Error, result?: any): void;
23
24 log?: any;
25 stack?: any;
26 missing?: any;
27}
28
29export type ResolverCallback = (request: Request, callback: Callback) => void;
30
31export interface ResolverPlugin {
32 apply(resolver: Resolver): void;
33}
34
35export interface Resolver {
36 apply(plugin: ResolverPlugin): void;
37 plugin(source: string, cb: ResolverCallback);
38 doResolve(target: string, req: Request, desc: string, Callback);
39 join(relativePath: string, innerRequest: Request): Request;
40}
41
42export interface Mapping {
43 onlyModule: boolean;
44 alias: string;
45 aliasPattern: RegExp;
46 target: string;
47}
48
49function escapeRegExp(str) {
50 return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
51}
52
53export interface PathPluginOptions {
54 context?: string;
55}
56
57export class PathPlugin implements ResolverPlugin {
58 source: string;
59 target: string;
60 ts: typeof ts;
61 configFilePath: string;
62 options: ts.CompilerOptions;
63
64 baseUrl: string;
65 mappings: Mapping[];
66 absoluteBaseUrl: string;
67
68 constructor(config: LoaderConfig & ts.CompilerOptions & PathPluginOptions = {} as any) {
69 this.source = 'described-resolve';
70 this.target = 'resolve';
71
72 this.ts = setupTs(config.compiler).tsImpl;
73
74 let context = config.context || process.cwd();
75 let { configFilePath, compilerConfig } = readConfigFile(context, config, {}, this.ts);
76
77 this.options = compilerConfig.options;
78 this.configFilePath = configFilePath;
79
80 this.baseUrl = this.options.baseUrl;
81 this.absoluteBaseUrl = path.resolve(
82 path.dirname(this.configFilePath),
83 this.baseUrl || '.'
84 );
85
86 this.mappings = [];
87 let paths = this.options.paths || {};
88 Object.keys(paths).forEach(alias => {
89 let onlyModule = alias.indexOf('*') === -1;
90 let excapedAlias = escapeRegExp(alias);
91 let targets = paths[alias];
92 targets.forEach(target => {
93 let aliasPattern: RegExp;
94 if (onlyModule) {
95 aliasPattern = new RegExp(`^${excapedAlias}$`);
96 } else {
97 let withStarCapturing = excapedAlias.replace('\\*', '(.*)');
98 aliasPattern = new RegExp(`^${withStarCapturing}`);
99 }
100
101 this.mappings.push({
102 onlyModule,
103 alias,
104 aliasPattern,
105 target: target
106 });
107 });
108 });
109 }
110
111 apply(resolver: Resolver) {
112 let { baseUrl, mappings } = this;
113
114 if (baseUrl) {
115 resolver.apply(new ModulesInRootPlugin("module", this.absoluteBaseUrl, "resolve"));
116 }
117
118 mappings.forEach(mapping => {
119 resolver.plugin(this.source, this.createPlugin(resolver, mapping));
120 });
121 }
122
123 createPlugin(resolver: Resolver, mapping: Mapping) {
124 return (request, callback) => {
125 let innerRequest = getInnerRequest(resolver, request);
126 if (!innerRequest) {
127 return callback();
128 }
129
130 let match = innerRequest.match(mapping.aliasPattern);
131 if (!match) {
132 return callback();
133 }
134
135 let newRequestStr = mapping.target;
136 if (!mapping.onlyModule) {
137 newRequestStr = newRequestStr.replace('*', match[1]);
138 }
139
140 if (newRequestStr[0] === '.') {
141 newRequestStr = path.resolve(this.absoluteBaseUrl, newRequestStr);
142 }
143
144 let newRequest = _.extend({}, request, {
145 request: newRequestStr
146 }) as Request;
147
148 return resolver.doResolve(
149 this.target,
150 newRequest,
151 "aliased with mapping '" + innerRequest + "': '" + mapping.alias + "' to '" + newRequestStr + "'",
152 createInnerCallback(
153 function(err, result) {
154 if (arguments.length > 0) {
155 return callback(err, result);
156 }
157
158 // don't allow other aliasing or raw request
159 callback(null, null);
160 },
161 callback
162 )
163 );
164 };
165 }
166}