UNPKG

4.84 kBJavaScriptView Raw
1// @flow strict-local
2
3import type {
4 SemverRange,
5 PackageJSON,
6 FilePath,
7 ModuleSpecifier,
8} from '@parcel/types';
9import type {ResolveOptions} from 'resolve';
10import type {FileSystem} from '@parcel/fs';
11
12// $FlowFixMe TODO: Type promisify
13import promisify from './promisify';
14import _resolve from 'resolve';
15import {resolveConfig, resolveConfigSync} from '../';
16// $FlowFixMe this is untyped
17import Module from 'module';
18
19const resolveAsync = promisify(_resolve);
20
21export type ResolveResult = {|
22 resolved: FilePath | ModuleSpecifier,
23 pkg?: ?PackageJSON,
24|};
25
26export async function resolve(
27 fs: FileSystem,
28 id: string,
29 opts: {|
30 range?: ?SemverRange,
31 ...ResolveOptions,
32 basedir: string,
33 |},
34): Promise<ResolveResult> {
35 if (process.env.PARCEL_BUILD_ENV !== 'production') {
36 // Yarn patches resolve automatically in a non-linked setup
37 let pnp;
38 if (
39 process.versions.pnp != null &&
40 (!id.includes('@parcel/') || id.startsWith('@parcel/watcher')) &&
41 (pnp = Module.findPnpApi(opts.basedir))
42 ) {
43 try {
44 let res = pnp.resolveRequest(id, `${opts.basedir}/`, {
45 extensions: opts.extensions,
46 considerBuiltins: true,
47 });
48
49 if (!res) {
50 // builtin
51 return {resolved: id};
52 }
53
54 let pkgFile = await resolveConfig(fs, res, ['package.json']);
55 let pkg = null;
56 if (pkgFile != null) {
57 pkg = JSON.parse(await fs.readFile(pkgFile, 'utf8'));
58 }
59
60 if (res) {
61 return {resolved: res, pkg};
62 }
63 } catch (e) {
64 if (e.code !== 'MODULE_NOT_FOUND') {
65 throw e;
66 }
67 }
68 }
69
70 // $FlowFixMe
71 opts.packageFilter = pkg => {
72 if (
73 typeof pkg.name === 'string' &&
74 pkg.name.startsWith('@parcel/') &&
75 pkg.name !== '@parcel/watcher'
76 ) {
77 if (pkg.source) {
78 pkg.main = pkg.source;
79 }
80 }
81 return pkg;
82 };
83 }
84
85 if (id === 'pnpapi') {
86 // the resolve package doesn't recognize pnpapi as a builtin
87 return {resolved: 'pnpapi'};
88 }
89
90 let res = await resolveAsync(id, {
91 ...opts,
92 async readFile(filename, callback) {
93 try {
94 let res = await fs.readFile(filename);
95 callback(null, res);
96 } catch (err) {
97 callback(err);
98 }
99 },
100 async isFile(file, callback) {
101 try {
102 let stat = await fs.stat(file);
103 callback(null, stat.isFile());
104 } catch (err) {
105 callback(null, false);
106 }
107 },
108 async isDirectory(file, callback) {
109 try {
110 let stat = await fs.stat(file);
111 callback(null, stat.isDirectory());
112 } catch (err) {
113 callback(null, false);
114 }
115 },
116 });
117
118 if (typeof res === 'string') {
119 return {
120 resolved: res,
121 };
122 }
123
124 return {
125 resolved: res[0],
126 pkg: res[1],
127 };
128}
129
130export function resolveSync(
131 fs: FileSystem,
132 id: string,
133 opts: {|
134 ...ResolveOptions,
135 basedir: string,
136 |},
137): ResolveResult {
138 if (process.env.PARCEL_BUILD_ENV !== 'production') {
139 // Yarn patches resolve automatically in a non-linked setup
140 let pnp;
141 if (
142 process.versions.pnp != null &&
143 (!id.startsWith('@parcel') || id.startsWith('@parcel/watcher')) &&
144 (pnp = Module.findPnpApi(opts.basedir))
145 ) {
146 try {
147 let res = pnp.resolveRequest(id, `${opts.basedir}/`, {
148 extensions: opts.extensions,
149 considerBuiltins: true,
150 });
151
152 if (!res) {
153 // builtin
154 return {resolved: id};
155 }
156
157 let pkgFile = resolveConfigSync(fs, res, ['package.json']);
158 let pkg = null;
159 if (pkgFile != null) {
160 pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf8'));
161 }
162
163 if (res) {
164 return {resolved: res, pkg};
165 }
166 } catch (e) {
167 if (e.code !== 'MODULE_NOT_FOUND') {
168 throw e;
169 }
170 }
171 }
172
173 // $FlowFixMe
174 opts.packageFilter = pkg => {
175 if (pkg.name.startsWith('@parcel/') && pkg.name !== '@parcel/watcher') {
176 if (pkg.source) {
177 pkg.main = pkg.source;
178 }
179 }
180 return pkg;
181 };
182 }
183
184 if (id === 'pnpapi') {
185 // the resolve package doesn't recognize pnpapi as a builtin
186 return {resolved: 'pnpapi'};
187 }
188
189 // $FlowFixMe
190 let res = _resolve.sync(id, {
191 ...opts,
192 readFileSync: (...args) => {
193 return fs.readFileSync(...args);
194 },
195 isFile: file => {
196 try {
197 let stat = fs.statSync(file);
198 return stat.isFile();
199 } catch (err) {
200 return false;
201 }
202 },
203 isDirectory: file => {
204 try {
205 let stat = fs.statSync(file);
206 return stat.isDirectory();
207 } catch (err) {
208 return false;
209 }
210 },
211 });
212
213 return {
214 resolved: res,
215 };
216}