1 |
|
2 |
|
3 | import type {
|
4 | SemverRange,
|
5 | PackageJSON,
|
6 | FilePath,
|
7 | ModuleSpecifier,
|
8 | } from '@parcel/types';
|
9 | import type {ResolveOptions} from 'resolve';
|
10 | import type {FileSystem} from '@parcel/fs';
|
11 |
|
12 |
|
13 | import promisify from './promisify';
|
14 | import _resolve from 'resolve';
|
15 | import {resolveConfig, resolveConfigSync} from '../';
|
16 |
|
17 | import Module from 'module';
|
18 |
|
19 | const resolveAsync = promisify(_resolve);
|
20 |
|
21 | export type ResolveResult = {|
|
22 | resolved: FilePath | ModuleSpecifier,
|
23 | pkg?: ?PackageJSON,
|
24 | |};
|
25 |
|
26 | export 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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
130 | export 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 |
|
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 |
|
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 |
|
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 |
|
186 | return {resolved: 'pnpapi'};
|
187 | }
|
188 |
|
189 |
|
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 | }
|