@jsenv/node-esm-resolution 0.1.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/node-esm-resolution",
3
- "version": "0.1.1",
3
+ "version": "1.0.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,11 +29,11 @@ export const determineModuleSystem = (
29
29
  return "url"
30
30
  }
31
31
  if (ambiguousExtensions.includes(extension)) {
32
- const packageUrl = defaultLookupPackageScope(url)
33
- if (!packageUrl) {
32
+ const packageDirectoryUrl = defaultLookupPackageScope(url)
33
+ if (!packageDirectoryUrl) {
34
34
  return "commonjs"
35
35
  }
36
- const packageJson = defaultReadPackageJson(packageUrl)
36
+ const packageJson = defaultReadPackageJson(packageDirectoryUrl)
37
37
  if (packageJson.type === "module") {
38
38
  return "module"
39
39
  }
package/src/errors.js CHANGED
@@ -1,11 +1,11 @@
1
1
  // https://github.com/nodejs/node/blob/0367b5c35ea0f98b323175a4aaa8e651af7a91e7/tools/node_modules/eslint/node_modules/%40babel/core/lib/vendor/import-meta-resolve.js#L2473
2
2
  import { fileURLToPath } from "node:url"
3
3
 
4
- export const createInvalidModuleSpecifierError = ({
5
- specifier,
6
- parentUrl,
4
+ export const createInvalidModuleSpecifierError = (
7
5
  reason,
8
- }) => {
6
+ specifier,
7
+ { parentUrl },
8
+ ) => {
9
9
  const error = new Error(
10
10
  `Invalid module "${specifier}" ${reason} imported from ${fileURLToPath(
11
11
  parentUrl,
@@ -15,24 +15,21 @@ export const createInvalidModuleSpecifierError = ({
15
15
  return error
16
16
  }
17
17
 
18
- export const createInvalidPackageTargetError = ({
19
- parentUrl,
20
- packageUrl,
21
- target,
22
- key,
23
- isImport,
18
+ export const createInvalidPackageTargetError = (
24
19
  reason,
25
- }) => {
20
+ target,
21
+ { parentUrl, packageDirectoryUrl, key, isImport },
22
+ ) => {
26
23
  let message
27
24
  if (key === ".") {
28
25
  message = `Invalid "exports" main target defined in ${fileURLToPath(
29
- packageUrl,
26
+ packageDirectoryUrl,
30
27
  )}package.json imported from ${fileURLToPath(parentUrl)}; ${reason}`
31
28
  } else {
32
29
  message = `Invalid "${
33
30
  isImport ? "imports" : "exports"
34
31
  }" target ${JSON.stringify(target)} defined for "${key}" in ${fileURLToPath(
35
- packageUrl,
32
+ packageDirectoryUrl,
36
33
  )}package.json imported from ${fileURLToPath(parentUrl)}; ${reason}`
37
34
  }
38
35
  const error = new Error(message)
@@ -40,19 +37,18 @@ export const createInvalidPackageTargetError = ({
40
37
  return error
41
38
  }
42
39
 
43
- export const createPackagePathNotExportedError = ({
40
+ export const createPackagePathNotExportedError = (
44
41
  subpath,
45
- parentUrl,
46
- packageUrl,
47
- }) => {
42
+ { parentUrl, packageDirectoryUrl },
43
+ ) => {
48
44
  let message
49
45
  if (subpath === ".") {
50
46
  message = `No "exports" main defined in ${fileURLToPath(
51
- packageUrl,
47
+ packageDirectoryUrl,
52
48
  )}package.json imported from ${fileURLToPath(parentUrl)}`
53
49
  } else {
54
50
  message = `Package subpath "${subpath}" is not defined by "exports" in ${fileURLToPath(
55
- packageUrl,
51
+ packageDirectoryUrl,
56
52
  )}package.json imported from ${fileURLToPath(parentUrl)}`
57
53
  }
58
54
  const error = new Error(message)
@@ -60,7 +56,7 @@ export const createPackagePathNotExportedError = ({
60
56
  return error
61
57
  }
62
58
 
63
- export const createModuleNotFoundError = ({ specifier, parentUrl }) => {
59
+ export const createModuleNotFoundError = (specifier, { parentUrl }) => {
64
60
  const error = new Error(
65
61
  `Cannot find "${specifier}" imported from ${fileURLToPath(parentUrl)}`,
66
62
  )
@@ -68,14 +64,13 @@ export const createModuleNotFoundError = ({ specifier, parentUrl }) => {
68
64
  return error
69
65
  }
70
66
 
71
- export const createPackageImportNotDefinedError = ({
67
+ export const createPackageImportNotDefinedError = (
72
68
  specifier,
73
- packageUrl,
74
- parentUrl,
75
- }) => {
69
+ { parentUrl, packageDirectoryUrl },
70
+ ) => {
76
71
  const error = new Error(
77
72
  `Package import specifier "${specifier}" is not defined in ${fileURLToPath(
78
- packageUrl,
73
+ packageDirectoryUrl,
79
74
  )}package.json imported from ${fileURLToPath(parentUrl)}`,
80
75
  )
81
76
  error.code = "PACKAGE_IMPORT_NOT_DEFINED"
@@ -9,7 +9,8 @@
9
9
  * maintain symlink as facade url when it's outside project directory
10
10
  * or use the real path when inside
11
11
  */
12
- import { existsSync, readFileSync } from "node:fs"
12
+ import { pathToFileURL } from "node:url"
13
+ import { existsSync, readFileSync, realpathSync } from "node:fs"
13
14
 
14
15
  import { isSpecifierForNodeBuiltin } from "./node_builtin_specifiers.js"
15
16
  import { defaultLookupPackageScope } from "./default_lookup_package_scope.js"
@@ -25,40 +26,38 @@ import {
25
26
  import { readCustomConditionsFromProcessArgs } from "./custom_conditions.js"
26
27
 
27
28
  export const applyNodeEsmResolution = ({
28
- conditions = [...readCustomConditionsFromProcessArgs(), "node", "import"],
29
- parentUrl,
30
29
  specifier,
30
+ parentUrl,
31
+ conditions = [...readCustomConditionsFromProcessArgs(), "node", "import"],
31
32
  lookupPackageScope = defaultLookupPackageScope,
32
33
  readPackageJson = defaultReadPackageJson,
34
+ preservesSymlink = false,
33
35
  }) => {
34
- const resolution = applyPackageSpecifierResolution({
35
- conditions,
36
+ const resolution = applyPackageSpecifierResolution(specifier, {
36
37
  parentUrl: String(parentUrl),
37
- specifier,
38
+ conditions,
38
39
  lookupPackageScope,
39
40
  readPackageJson,
41
+ preservesSymlink,
40
42
  })
41
43
  const { url } = resolution
42
44
  if (url.startsWith("file:")) {
43
45
  if (url.includes("%2F") || url.includes("%5C")) {
44
- throw createInvalidModuleSpecifierError({
46
+ throw createInvalidModuleSpecifierError(
47
+ `must not include encoded "/" or "\\" characters`,
45
48
  specifier,
46
- parentUrl,
47
- reason: `must not include encoded "/" or "\\" characters`,
48
- })
49
+ {
50
+ parentUrl,
51
+ },
52
+ )
49
53
  }
50
54
  return resolution
51
55
  }
52
56
  return resolution
53
57
  }
54
58
 
55
- const applyPackageSpecifierResolution = ({
56
- conditions,
57
- parentUrl,
58
- specifier,
59
- lookupPackageScope,
60
- readPackageJson,
61
- }) => {
59
+ const applyPackageSpecifierResolution = (specifier, resolutionContext) => {
60
+ const { parentUrl } = resolutionContext
62
61
  // relative specifier
63
62
  if (
64
63
  specifier[0] === "/" ||
@@ -66,13 +65,10 @@ const applyPackageSpecifierResolution = ({
66
65
  specifier.startsWith("../")
67
66
  ) {
68
67
  if (specifier[0] !== "/") {
69
- const browserFieldResolution = applyBrowserFieldResolution({
70
- conditions,
71
- parentUrl,
68
+ const browserFieldResolution = applyBrowserFieldResolution(
72
69
  specifier,
73
- lookupPackageScope,
74
- readPackageJson,
75
- })
70
+ resolutionContext,
71
+ )
76
72
  if (browserFieldResolution) {
77
73
  return browserFieldResolution
78
74
  }
@@ -83,13 +79,7 @@ const applyPackageSpecifierResolution = ({
83
79
  }
84
80
  }
85
81
  if (specifier[0] === "#") {
86
- return applyPackageImportsResolution({
87
- conditions,
88
- parentUrl,
89
- specifier,
90
- lookupPackageScope,
91
- readPackageJson,
92
- })
82
+ return applyPackageImportsResolution(specifier, resolutionContext)
93
83
  }
94
84
  try {
95
85
  const urlObject = new URL(specifier)
@@ -105,42 +95,34 @@ const applyPackageSpecifierResolution = ({
105
95
  }
106
96
  } catch (e) {
107
97
  // bare specifier
108
- const browserFieldResolution = applyBrowserFieldResolution({
109
- conditions,
110
- parentUrl,
111
- packageSpecifier: specifier,
112
- lookupPackageScope,
113
- readPackageJson,
114
- })
98
+ const browserFieldResolution = applyBrowserFieldResolution(
99
+ specifier,
100
+ resolutionContext,
101
+ )
115
102
  if (browserFieldResolution) {
116
103
  return browserFieldResolution
117
104
  }
118
- return applyPackageResolve({
119
- conditions,
120
- parentUrl,
121
- packageSpecifier: specifier,
122
- lookupPackageScope,
123
- readPackageJson,
124
- })
105
+ const packageResolution = applyPackageResolve(specifier, resolutionContext)
106
+ const search = new URL(specifier, "file://").search
107
+ if (search) {
108
+ packageResolution.url = `${packageResolution.url}${search}`
109
+ }
110
+ return packageResolution
125
111
  }
126
112
  }
127
113
 
128
- const applyBrowserFieldResolution = ({
129
- conditions,
130
- parentUrl,
131
- packageSpecifier,
132
- lookupPackageScope,
133
- readPackageJson,
134
- }) => {
114
+ const applyBrowserFieldResolution = (specifier, resolutionContext) => {
115
+ const { parentUrl, conditions, lookupPackageScope, readPackageJson } =
116
+ resolutionContext
135
117
  const browserCondition = conditions.includes("browser")
136
118
  if (!browserCondition) {
137
119
  return null
138
120
  }
139
- const packageUrl = lookupPackageScope(parentUrl)
140
- if (!packageUrl) {
121
+ const packageDirectoryUrl = lookupPackageScope(parentUrl)
122
+ if (!packageDirectoryUrl) {
141
123
  return null
142
124
  }
143
- const packageJson = readPackageJson(packageUrl)
125
+ const packageJson = readPackageJson(packageDirectoryUrl)
144
126
  if (!packageJson) {
145
127
  return null
146
128
  }
@@ -152,30 +134,28 @@ const applyBrowserFieldResolution = ({
152
134
  return null
153
135
  }
154
136
  let url
155
- if (packageSpecifier.startsWith(".")) {
156
- const packageSpecifierUrl = new URL(packageSpecifier, parentUrl).href
157
- const packageSpecifierRelativeUrl = packageSpecifierUrl.slice(
158
- packageUrl.length,
159
- )
160
- const packageSpecifierRelativeNotation = `./${packageSpecifierRelativeUrl}`
161
- const browserMapping = browser[packageSpecifierRelativeNotation]
137
+ if (specifier.startsWith(".")) {
138
+ const specifierUrl = new URL(specifier, parentUrl).href
139
+ const specifierRelativeUrl = specifierUrl.slice(packageDirectoryUrl.length)
140
+ const secifierRelativeNotation = `./${specifierRelativeUrl}`
141
+ const browserMapping = browser[secifierRelativeNotation]
162
142
  if (typeof browserMapping === "string") {
163
- url = new URL(browserMapping, packageUrl).href
143
+ url = new URL(browserMapping, packageDirectoryUrl).href
164
144
  } else if (browserMapping === false) {
165
- url = `file:///@ignore/${packageSpecifierUrl.slice("file:///")}`
145
+ url = `file:///@ignore/${specifierUrl.slice("file:///")}`
166
146
  }
167
147
  } else {
168
- const browserMapping = browser[packageSpecifier]
148
+ const browserMapping = browser[specifier]
169
149
  if (typeof browserMapping === "string") {
170
- url = new URL(browserMapping, packageUrl).href
150
+ url = new URL(browserMapping, packageDirectoryUrl).href
171
151
  } else if (browserMapping === false) {
172
- url = `file:///@ignore/${packageSpecifier}`
152
+ url = `file:///@ignore/${specifier}`
173
153
  }
174
154
  }
175
155
  if (url) {
176
156
  return {
177
157
  type: "field:browser",
178
- packageUrl,
158
+ packageDirectoryUrl,
179
159
  packageJson,
180
160
  url,
181
161
  }
@@ -183,62 +163,43 @@ const applyBrowserFieldResolution = ({
183
163
  return null
184
164
  }
185
165
 
186
- const applyPackageImportsResolution = ({
187
- conditions,
188
- parentUrl,
189
- specifier,
190
- lookupPackageScope,
191
- readPackageJson,
192
- }) => {
193
- if (!specifier.startsWith("#")) {
194
- throw createInvalidModuleSpecifierError({
195
- specifier,
196
- parentUrl,
197
- reason: "internal imports must start with #",
198
- })
199
- }
200
- if (specifier === "#" || specifier.startsWith("#/")) {
201
- throw createInvalidModuleSpecifierError({
202
- specifier,
203
- parentUrl,
204
- reason: "not a valid internal imports specifier name",
205
- })
166
+ const applyPackageImportsResolution = (
167
+ internalSpecifier,
168
+ resolutionContext,
169
+ ) => {
170
+ const { parentUrl, lookupPackageScope, readPackageJson } = resolutionContext
171
+ if (internalSpecifier === "#" || internalSpecifier.startsWith("#/")) {
172
+ throw createInvalidModuleSpecifierError(
173
+ "not a valid internal imports specifier name",
174
+ internalSpecifier,
175
+ resolutionContext,
176
+ )
206
177
  }
207
- const packageUrl = lookupPackageScope(parentUrl)
208
- if (packageUrl !== null) {
209
- const packageJson = readPackageJson(packageUrl)
178
+ const packageDirectoryUrl = lookupPackageScope(parentUrl)
179
+ if (packageDirectoryUrl !== null) {
180
+ const packageJson = readPackageJson(packageDirectoryUrl)
210
181
  const { imports } = packageJson
211
182
  if (imports !== null && typeof imports === "object") {
212
- const resolved = applyPackageImportsExportsResolution({
213
- conditions,
214
- parentUrl,
215
- packageUrl,
183
+ const resolved = applyPackageImportsExportsResolution(internalSpecifier, {
184
+ ...resolutionContext,
185
+ packageDirectoryUrl,
216
186
  packageJson,
217
- matchObject: imports,
218
- matchKey: specifier,
219
- isImports: true,
220
- lookupPackageScope,
221
- readPackageJson,
187
+ isImport: true,
222
188
  })
223
189
  if (resolved) {
224
190
  return resolved
225
191
  }
226
192
  }
227
193
  }
228
- throw createPackageImportNotDefinedError({
229
- specifier,
230
- packageUrl,
231
- parentUrl,
194
+ throw createPackageImportNotDefinedError(internalSpecifier, {
195
+ ...resolutionContext,
196
+ packageDirectoryUrl,
232
197
  })
233
198
  }
234
199
 
235
- const applyPackageResolve = ({
236
- conditions,
237
- parentUrl,
238
- packageSpecifier,
239
- lookupPackageScope,
240
- readPackageJson,
241
- }) => {
200
+ const applyPackageResolve = (packageSpecifier, resolutionContext) => {
201
+ const { parentUrl, conditions, readPackageJson, preservesSymlink } =
202
+ resolutionContext
242
203
  if (packageSpecifier === "") {
243
204
  throw new Error("invalid module specifier")
244
205
  }
@@ -258,78 +219,64 @@ const applyPackageResolve = ({
258
219
  packageName.includes("\\") ||
259
220
  packageName.includes("%")
260
221
  ) {
261
- throw createInvalidModuleSpecifierError({
262
- specifier: packageName,
263
- parentUrl,
264
- reason: `is not a valid package name`,
265
- })
222
+ throw createInvalidModuleSpecifierError(
223
+ `is not a valid package name`,
224
+ packageName,
225
+ resolutionContext,
226
+ )
266
227
  }
267
228
  if (packageSubpath.endsWith("/")) {
268
229
  throw new Error("invalid module specifier")
269
230
  }
270
- const selfResolution = applyPackageSelfResolution({
271
- conditions,
272
- parentUrl,
231
+ const selfResolution = applyPackageSelfResolution(packageSubpath, {
232
+ ...resolutionContext,
273
233
  packageName,
274
- packageSubpath,
275
- lookupPackageScope,
276
- readPackageJson,
277
234
  })
278
235
  if (selfResolution) {
279
236
  return selfResolution
280
237
  }
281
238
  let currentUrl = parentUrl
282
239
  while (currentUrl !== "file:///") {
283
- const packageUrl = new URL(`node_modules/${packageName}/`, currentUrl).href
284
- if (!existsSync(new URL(packageUrl))) {
240
+ const packageDirectoryFacadeUrl = new URL(
241
+ `node_modules/${packageName}/`,
242
+ currentUrl,
243
+ ).href
244
+ if (!existsSync(new URL(packageDirectoryFacadeUrl))) {
285
245
  currentUrl = getParentUrl(currentUrl)
286
246
  continue
287
247
  }
288
- const packageJson = readPackageJson(packageUrl)
248
+ const packageDirectoryUrl = preservesSymlink
249
+ ? packageDirectoryFacadeUrl
250
+ : resolvePackageSymlink(packageDirectoryFacadeUrl)
251
+ const packageJson = readPackageJson(packageDirectoryUrl)
289
252
  if (packageJson !== null) {
290
253
  const { exports } = packageJson
291
254
  if (exports !== null && exports !== undefined) {
292
- return applyPackageExportsResolution({
293
- conditions,
294
- parentUrl,
295
- packageUrl,
255
+ return applyPackageExportsResolution(packageSubpath, {
256
+ ...resolutionContext,
257
+ packageDirectoryUrl,
296
258
  packageJson,
297
- packageSubpath,
298
259
  exports,
299
- lookupPackageScope,
300
- readPackageJson,
301
260
  })
302
261
  }
303
262
  }
304
- return applyLegacySubpathResolution({
305
- conditions,
306
- parentUrl,
307
- packageUrl,
263
+ return applyLegacySubpathResolution(packageSubpath, {
264
+ ...resolutionContext,
265
+ packageDirectoryUrl,
308
266
  packageJson,
309
- packageSubpath,
310
- lookupPackageScope,
311
- readPackageJson,
312
267
  })
313
268
  }
314
- throw createModuleNotFoundError({
315
- specifier: packageName,
316
- parentUrl,
317
- })
269
+ throw createModuleNotFoundError(packageName, resolutionContext)
318
270
  }
319
271
 
320
- const applyPackageSelfResolution = ({
321
- conditions,
322
- parentUrl,
323
- packageName,
324
- packageSubpath,
325
- lookupPackageScope,
326
- readPackageJson,
327
- }) => {
328
- const packageUrl = lookupPackageScope(parentUrl)
329
- if (!packageUrl) {
272
+ const applyPackageSelfResolution = (packageSubpath, resolutionContext) => {
273
+ const { parentUrl, packageName, lookupPackageScope, readPackageJson } =
274
+ resolutionContext
275
+ const packageDirectoryUrl = lookupPackageScope(parentUrl)
276
+ if (!packageDirectoryUrl) {
330
277
  return undefined
331
278
  }
332
- const packageJson = readPackageJson(packageUrl)
279
+ const packageJson = readPackageJson(packageDirectoryUrl)
333
280
  if (!packageJson) {
334
281
  return undefined
335
282
  }
@@ -338,118 +285,65 @@ const applyPackageSelfResolution = ({
338
285
  }
339
286
  const { exports } = packageJson
340
287
  if (!exports) {
341
- const subpathResolution = applyLegacySubpathResolution({
342
- conditions,
343
- parentUrl,
344
- packageUrl,
288
+ const subpathResolution = applyLegacySubpathResolution(packageSubpath, {
289
+ ...resolutionContext,
290
+ packageDirectoryUrl,
345
291
  packageJson,
346
- packageSubpath,
347
- lookupPackageScope,
348
- readPackageJson,
349
292
  })
350
293
  if (subpathResolution && subpathResolution.type !== "subpath") {
351
294
  return subpathResolution
352
295
  }
353
296
  return undefined
354
297
  }
355
- return applyPackageExportsResolution({
356
- conditions,
357
- parentUrl,
358
- packageUrl,
298
+ return applyPackageExportsResolution(packageSubpath, {
299
+ ...resolutionContext,
300
+ packageDirectoryUrl,
359
301
  packageJson,
360
- packageSubpath,
361
- exports,
362
- lookupPackageScope,
363
- readPackageJson,
364
302
  })
365
303
  }
366
304
 
367
305
  // https://github.com/nodejs/node/blob/0367b5c35ea0f98b323175a4aaa8e651af7a91e7/lib/internal/modules/esm/resolve.js#L642
368
- const applyPackageExportsResolution = ({
369
- conditions,
370
- parentUrl,
371
- packageUrl,
372
- packageJson,
373
- packageSubpath,
374
- exports,
375
- lookupPackageScope,
376
- readPackageJson,
377
- }) => {
378
- const exportsInfo = readExports({ exports, packageUrl })
306
+ const applyPackageExportsResolution = (packageSubpath, resolutionContext) => {
379
307
  if (packageSubpath === ".") {
380
- const mainExport = applyMainExportResolution({ exports, exportsInfo })
308
+ const mainExport = applyMainExportResolution(resolutionContext)
381
309
  if (!mainExport) {
382
- throw createPackagePathNotExportedError({
383
- subpath: packageSubpath,
384
- parentUrl,
385
- packageUrl,
386
- })
310
+ throw createPackagePathNotExportedError(packageSubpath, resolutionContext)
387
311
  }
388
- const resolved = applyPackageTargetResolution({
389
- conditions,
390
- parentUrl,
391
- packageUrl,
392
- packageJson,
312
+ const resolved = applyPackageTargetResolution(mainExport, {
313
+ ...resolutionContext,
393
314
  key: ".",
394
- target: mainExport,
395
- lookupPackageScope,
396
- readPackageJson,
397
315
  })
398
316
  if (resolved) {
399
317
  return resolved
400
318
  }
401
- throw createPackagePathNotExportedError({
402
- subpath: packageSubpath,
403
- parentUrl,
404
- packageUrl,
405
- })
319
+ throw createPackagePathNotExportedError(packageSubpath, resolutionContext)
406
320
  }
407
- if (exportsInfo.type === "object" && exportsInfo.allKeysAreRelative) {
408
- const resolved = applyPackageImportsExportsResolution({
409
- conditions,
410
- parentUrl,
411
- packageUrl,
412
- packageJson,
413
- matchObject: exports,
414
- matchKey: packageSubpath,
415
- isImports: false,
416
- lookupPackageScope,
417
- readPackageJson,
321
+ const packageExportsInfo = readExports(resolutionContext)
322
+ if (
323
+ packageExportsInfo.type === "object" &&
324
+ packageExportsInfo.allKeysAreRelative
325
+ ) {
326
+ const resolved = applyPackageImportsExportsResolution(packageSubpath, {
327
+ ...resolutionContext,
328
+ isImport: false,
418
329
  })
419
330
  if (resolved) {
420
331
  return resolved
421
332
  }
422
333
  }
423
- throw createPackagePathNotExportedError({
424
- subpath: packageSubpath,
425
- parentUrl,
426
- packageUrl,
427
- })
334
+ throw createPackagePathNotExportedError(packageSubpath, resolutionContext)
428
335
  }
429
336
 
430
- const applyPackageImportsExportsResolution = ({
431
- conditions,
432
- parentUrl,
433
- packageUrl,
434
- packageJson,
435
- matchObject,
436
- matchKey,
437
- isImports,
438
- lookupPackageScope,
439
- readPackageJson,
440
- }) => {
337
+ const applyPackageImportsExportsResolution = (matchKey, resolutionContext) => {
338
+ const { packageJson, isImport } = resolutionContext
339
+ const matchObject = isImport ? packageJson.imports : packageJson.exports
340
+
441
341
  if (!matchKey.includes("*") && matchObject.hasOwnProperty(matchKey)) {
442
342
  const target = matchObject[matchKey]
443
- return applyPackageTargetResolution({
444
- conditions,
445
- parentUrl,
446
- packageUrl,
447
- packageJson,
343
+ return applyPackageTargetResolution(target, {
344
+ ...resolutionContext,
448
345
  key: matchKey,
449
- target,
450
- internal: isImports,
451
- lookupPackageScope,
452
- readPackageJson,
346
+ isImport,
453
347
  })
454
348
  }
455
349
  const expansionKeys = Object.keys(matchObject)
@@ -468,80 +362,64 @@ const applyPackageImportsExportsResolution = ({
468
362
  patternBase.length,
469
363
  matchKey.length - patternTrailer.length,
470
364
  )
471
- return applyPackageTargetResolution({
472
- conditions,
473
- parentUrl,
474
- packageUrl,
475
- packageJson,
365
+ return applyPackageTargetResolution(target, {
366
+ ...resolutionContext,
476
367
  key: matchKey,
477
- target,
478
368
  subpath,
479
369
  pattern: true,
480
- internal: isImports,
481
- lookupPackageScope,
482
- readPackageJson,
370
+ isImport,
483
371
  })
484
372
  }
485
373
  return null
486
374
  }
487
375
 
488
- const applyPackageTargetResolution = ({
489
- conditions,
490
- parentUrl,
491
- packageUrl,
492
- packageJson,
493
- key,
494
- target,
495
- subpath = "",
496
- pattern = false,
497
- internal = false,
498
- lookupPackageScope,
499
- readPackageJson,
500
- }) => {
376
+ const applyPackageTargetResolution = (target, resolutionContext) => {
377
+ const {
378
+ conditions,
379
+ packageDirectoryUrl,
380
+ packageJson,
381
+ key,
382
+ subpath = "",
383
+ pattern = false,
384
+ isImport = false,
385
+ } = resolutionContext
386
+
501
387
  if (typeof target === "string") {
502
388
  if (pattern === false && subpath !== "" && !target.endsWith("/")) {
503
389
  throw new Error("invalid module specifier")
504
390
  }
505
391
  if (target.startsWith("./")) {
506
- const targetUrl = new URL(target, packageUrl).href
507
- if (!targetUrl.startsWith(packageUrl)) {
508
- throw createInvalidPackageTargetError({
509
- parentUrl,
510
- packageUrl,
392
+ const targetUrl = new URL(target, packageDirectoryUrl).href
393
+ if (!targetUrl.startsWith(packageDirectoryUrl)) {
394
+ throw createInvalidPackageTargetError(
395
+ `target must be inside package`,
511
396
  target,
512
- key,
513
- isImport: internal,
514
- reason: `target must be inside package`,
515
- })
397
+ resolutionContext,
398
+ )
516
399
  }
517
400
  return {
518
- type: internal ? "field:imports" : "field:exports",
519
- packageUrl,
401
+ type: isImport ? "field:imports" : "field:exports",
402
+ packageDirectoryUrl,
520
403
  packageJson,
521
404
  url: pattern
522
405
  ? targetUrl.replaceAll("*", subpath)
523
406
  : new URL(subpath, targetUrl).href,
524
407
  }
525
408
  }
526
- if (!internal || target.startsWith("../") || isValidUrl(target)) {
527
- throw createInvalidPackageTargetError({
528
- parentUrl,
529
- packageUrl,
409
+ if (!isImport || target.startsWith("../") || isValidUrl(target)) {
410
+ throw createInvalidPackageTargetError(
411
+ `target must starst with "./"`,
530
412
  target,
531
- key,
532
- isImport: internal,
533
- reason: `target must starst with "./"`,
534
- })
413
+ resolutionContext,
414
+ )
535
415
  }
536
- return applyPackageResolve({
537
- conditions,
538
- parentUrl: packageUrl,
539
- packageSpecifier: pattern
540
- ? target.replaceAll("*", subpath)
541
- : `${target}${subpath}`,
542
- lookupPackageScope,
543
- readPackageJson,
544
- })
416
+ return applyPackageResolve(
417
+ pattern ? target.replaceAll("*", subpath) : `${target}${subpath}`,
418
+ {
419
+ ...resolutionContext,
420
+ parentUrl: packageDirectoryUrl,
421
+ },
422
+ )
545
423
  }
546
424
  if (Array.isArray(target)) {
547
425
  if (target.length === 0) {
@@ -553,18 +431,12 @@ const applyPackageTargetResolution = ({
553
431
  const targetValue = target[i]
554
432
  i++
555
433
  try {
556
- const resolved = applyPackageTargetResolution({
557
- conditions,
558
- parentUrl,
559
- packageUrl,
560
- packageJson,
434
+ const resolved = applyPackageTargetResolution(targetValue, {
435
+ ...resolutionContext,
561
436
  key: `${key}[${i}]`,
562
- target: targetValue,
563
437
  subpath,
564
438
  pattern,
565
- internal,
566
- lookupPackageScope,
567
- readPackageJson,
439
+ isImport,
568
440
  })
569
441
  if (resolved) {
570
442
  return resolved
@@ -593,18 +465,12 @@ const applyPackageTargetResolution = ({
593
465
  }
594
466
  if (key === "default" || conditions.includes(key)) {
595
467
  const targetValue = target[key]
596
- const resolved = applyPackageTargetResolution({
597
- conditions,
598
- parentUrl,
599
- packageUrl,
600
- packageJson,
468
+ const resolved = applyPackageTargetResolution(targetValue, {
469
+ ...resolutionContext,
601
470
  key,
602
- target: targetValue,
603
471
  subpath,
604
472
  pattern,
605
- internal,
606
- lookupPackageScope,
607
- readPackageJson,
473
+ isImport,
608
474
  })
609
475
  if (resolved) {
610
476
  return resolved
@@ -613,27 +479,25 @@ const applyPackageTargetResolution = ({
613
479
  }
614
480
  return null
615
481
  }
616
- throw createInvalidPackageTargetError({
617
- parentUrl,
618
- packageUrl,
482
+ throw createInvalidPackageTargetError(
483
+ `target must be a string, array, object or null`,
619
484
  target,
620
- key,
621
- isImport: internal,
622
- reason: `target must be a string, array, object or null`,
623
- })
485
+ resolutionContext,
486
+ )
624
487
  }
625
488
 
626
- const readExports = ({ exports, packageUrl }) => {
627
- if (Array.isArray(exports)) {
489
+ const readExports = ({ packageDirectoryUrl, packageJson }) => {
490
+ const packageExports = packageJson.exports
491
+ if (Array.isArray(packageExports)) {
628
492
  return {
629
493
  type: "array",
630
494
  }
631
495
  }
632
- if (exports === null) {
496
+ if (packageExports === null) {
633
497
  return {}
634
498
  }
635
- if (typeof exports === "object") {
636
- const keys = Object.keys(exports)
499
+ if (typeof packageExports === "object") {
500
+ const keys = Object.keys(packageExports)
637
501
  const relativeKeys = []
638
502
  const conditionalKeys = []
639
503
  keys.forEach((availableKey) => {
@@ -649,8 +513,8 @@ const readExports = ({ exports, packageUrl }) => {
649
513
  `Invalid package configuration: cannot mix relative and conditional keys in package.exports
650
514
  --- unexpected keys ---
651
515
  ${conditionalKeys.map((key) => `"${key}"`).join("\n")}
652
- --- package.json ---
653
- ${packageUrl}`,
516
+ --- package directory url ---
517
+ ${packageDirectoryUrl}`,
654
518
  )
655
519
  }
656
520
  return {
@@ -659,7 +523,7 @@ ${packageUrl}`,
659
523
  allKeysAreRelative: relativeKeys.length === keys.length,
660
524
  }
661
525
  }
662
- if (typeof exports === "string") {
526
+ if (typeof packageExports === "string") {
663
527
  return { type: "string" }
664
528
  }
665
529
  return {}
@@ -704,78 +568,71 @@ const parsePackageSpecifier = (packageSpecifier) => {
704
568
  }
705
569
  }
706
570
 
707
- const applyMainExportResolution = ({ exports, exportsInfo }) => {
708
- if (exportsInfo.type === "array" || exportsInfo.type === "string") {
709
- return exports
571
+ const applyMainExportResolution = (resolutionContext) => {
572
+ const { packageJson } = resolutionContext
573
+ const packageExportsInfo = readExports(resolutionContext)
574
+ if (
575
+ packageExportsInfo.type === "array" ||
576
+ packageExportsInfo.type === "string"
577
+ ) {
578
+ return packageJson.exports
710
579
  }
711
- if (exportsInfo.type === "object") {
712
- if (exportsInfo.hasRelativeKey) {
713
- return exports["."]
580
+ if (packageExportsInfo.type === "object") {
581
+ if (packageExportsInfo.hasRelativeKey) {
582
+ return packageJson.exports["."]
714
583
  }
715
- return exports
584
+ return packageJson.exports
716
585
  }
717
586
  return undefined
718
587
  }
719
588
 
720
- const applyLegacySubpathResolution = ({
721
- conditions,
722
- parentUrl,
723
- packageUrl,
724
- packageJson,
725
- packageSubpath,
726
- lookupPackageScope,
727
- readPackageJson,
728
- }) => {
589
+ const applyLegacySubpathResolution = (packageSubpath, resolutionContext) => {
590
+ const { packageDirectoryUrl, packageJson } = resolutionContext
591
+
729
592
  if (packageSubpath === ".") {
730
- return applyLegacyMainResolution({
731
- conditions,
732
- packageUrl,
733
- packageJson,
734
- })
593
+ return applyLegacyMainResolution(packageSubpath, resolutionContext)
735
594
  }
736
- const browserFieldResolution = applyBrowserFieldResolution({
737
- conditions,
738
- parentUrl,
739
- specifier: packageSubpath,
740
- lookupPackageScope,
741
- readPackageJson,
742
- })
595
+ const browserFieldResolution = applyBrowserFieldResolution(
596
+ packageSubpath,
597
+ resolutionContext,
598
+ )
743
599
  if (browserFieldResolution) {
744
600
  return browserFieldResolution
745
601
  }
746
602
  return {
747
603
  type: "subpath",
748
- packageUrl,
604
+ packageDirectoryUrl,
749
605
  packageJson,
750
- url: new URL(packageSubpath, packageUrl).href,
606
+ url: new URL(packageSubpath, packageDirectoryUrl).href,
751
607
  }
752
608
  }
753
609
 
754
- const applyLegacyMainResolution = ({ conditions, packageUrl, packageJson }) => {
610
+ const applyLegacyMainResolution = (packageSubpath, resolutionContext) => {
611
+ const { conditions, packageDirectoryUrl, packageJson } = resolutionContext
755
612
  for (const condition of conditions) {
756
613
  const conditionResolver = mainLegacyResolvers[condition]
757
614
  if (!conditionResolver) {
758
615
  continue
759
616
  }
760
- const resolved = conditionResolver(packageJson, packageUrl)
617
+ const resolved = conditionResolver(resolutionContext)
761
618
  if (resolved) {
762
619
  return {
763
620
  type: resolved.type,
764
- packageUrl,
621
+ packageDirectoryUrl,
765
622
  packageJson,
766
- url: new URL(resolved.path, packageUrl).href,
623
+ url: new URL(resolved.path, packageDirectoryUrl).href,
767
624
  }
768
625
  }
769
626
  }
770
627
  return {
771
628
  type: "field:main", // the absence of "main" field
772
- packageUrl,
629
+ packageDirectoryUrl,
773
630
  packageJson,
774
- url: new URL("index.js", packageUrl).href,
631
+ url: new URL("index.js", packageDirectoryUrl).href,
775
632
  }
776
633
  }
777
634
  const mainLegacyResolvers = {
778
- import: (packageJson) => {
635
+ import: ({ packageJson }) => {
779
636
  if (typeof packageJson.module === "string") {
780
637
  return { type: "field:module", path: packageJson.module }
781
638
  }
@@ -787,7 +644,7 @@ const mainLegacyResolvers = {
787
644
  }
788
645
  return null
789
646
  },
790
- browser: (packageJson, packageUrl) => {
647
+ browser: ({ packageDirectoryUrl, packageJson }) => {
791
648
  const browserMain = (() => {
792
649
  if (typeof packageJson.browser === "string") {
793
650
  return packageJson.browser
@@ -819,7 +676,7 @@ const mainLegacyResolvers = {
819
676
  path: browserMain,
820
677
  }
821
678
  }
822
- const browserMainUrlObject = new URL(browserMain, packageUrl)
679
+ const browserMainUrlObject = new URL(browserMain, packageDirectoryUrl)
823
680
  const content = readFileSync(browserMainUrlObject, "utf-8")
824
681
  if (
825
682
  (/typeof exports\s*==/.test(content) &&
@@ -836,7 +693,7 @@ const mainLegacyResolvers = {
836
693
  path: browserMain,
837
694
  }
838
695
  },
839
- node: (packageJson) => {
696
+ node: ({ packageJson }) => {
840
697
  if (typeof packageJson.main === "string") {
841
698
  return {
842
699
  type: "field:main",
@@ -878,3 +735,9 @@ const comparePatternKeys = (keyA, keyB) => {
878
735
  }
879
736
  return 0
880
737
  }
738
+
739
+ const resolvePackageSymlink = (packageDirectoryUrl) => {
740
+ const packageDirectoryPath = realpathSync(new URL(packageDirectoryUrl))
741
+ const packageDirectoryResolvedUrl = pathToFileURL(packageDirectoryPath).href
742
+ return `${packageDirectoryResolvedUrl}/`
743
+ }