Skip to content

Commit dbb53a5

Browse files
committed
Backport changes from Node
This doesn’t really change anything, just a different error and some refactoring. f13dbfd43a044fcd71adb88ab437274d59a8e362 416333fd503970227522602d5728d1ab31c81e3c a717fa211194b735cdfc1044c7351c6cf96b8783 3fbe1579ce0c9842250f01392dcffc0c15af1924 f4a0a3b04b92596fd2cf40e1d9c5a003e81c77b8 651fa047c1035416c2992989a04a84cc5425465b fc2862b7f55bbc0e54092423e5272c213df0ed32 ad0bcb9c0276d21869b09a38b0e8bed549d4367d 075c95f61f2be5b8571fe4c6fcf9c3744d0188a9 d6b57f6629da5616362be60ae0f3e9510a7f700e a596af0819aeb9d607a722eaaa5a06aa9b22caec
1 parent 80d8920 commit dbb53a5

File tree

8 files changed

+111
-116
lines changed

8 files changed

+111
-116
lines changed

lib/errors.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,12 @@ codes.ERR_UNSUPPORTED_DIR_IMPORT = createError(
282282
Error
283283
)
284284

285+
codes.ERR_UNSUPPORTED_RESOLVE_REQUEST = createError(
286+
'ERR_UNSUPPORTED_RESOLVE_REQUEST',
287+
'Failed to resolve module specifier "%s" from "%s": Invalid relative URL or base scheme is not hierarchical.',
288+
TypeError
289+
)
290+
285291
codes.ERR_UNKNOWN_FILE_EXTENSION = createError(
286292
'ERR_UNKNOWN_FILE_EXTENSION',
287293
/**

lib/get-format.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// Manually “tree shaken” from:
2-
// <https://github.com/nodejs/node/blob/45f5c9b/lib/internal/modules/esm/get_format.js>
3-
// Last checked on: Nov 2, 2023.
2+
// <https://github.com/nodejs/node/blob/7c3dce0/lib/internal/modules/esm/get_format.js>
3+
// Last checked on: Apr 29, 2023.
44

55
import {fileURLToPath} from 'node:url'
6-
import {getPackageType} from './resolve-get-package-type.js'
6+
import {getPackageType} from './package-json-reader.js'
77
import {codes} from './errors.js'
88

99
const {ERR_UNKNOWN_FILE_EXTENSION} = codes

lib/package-config.js

Lines changed: 0 additions & 55 deletions
This file was deleted.

lib/package-json-reader.js

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Manually “tree shaken” from:
2-
// <https://github.com/nodejs/node/blob/45f5c9b/lib/internal/modules/package_json_reader.js>
3-
// Last checked on: Nov 2, 2023.
2+
// <https://github.com/nodejs/node/blob/7c3dce0/lib/internal/modules/package_json_reader.js>
3+
// Last checked on: Apr 29, 2023.
44
// Removed the native dependency.
55
// Also: no need to cache, we do that in resolve already.
66

@@ -12,11 +12,11 @@
1212
* @typedef PackageConfig
1313
* @property {string} pjsonPath
1414
* @property {boolean} exists
15-
* @property {string | undefined} main
16-
* @property {string | undefined} name
15+
* @property {string | undefined} [main]
16+
* @property {string | undefined} [name]
1717
* @property {PackageType} type
18-
* @property {Record<string, unknown> | undefined} exports
19-
* @property {Record<string, unknown> | undefined} imports
18+
* @property {Record<string, unknown> | undefined} [exports]
19+
* @property {Record<string, unknown> | undefined} [imports]
2020
*/
2121

2222
import fs from 'node:fs'
@@ -31,15 +31,12 @@ const {ERR_INVALID_PACKAGE_CONFIG} = codes
3131
/** @type {Map<string, PackageConfig>} */
3232
const cache = new Map()
3333

34-
const reader = {read}
35-
export default reader
36-
3734
/**
3835
* @param {string} jsonPath
3936
* @param {{specifier: URL | string, base?: URL}} options
4037
* @returns {PackageConfig}
4138
*/
42-
function read(jsonPath, {base, specifier}) {
39+
export function read(jsonPath, {base, specifier}) {
4340
const existing = cache.get(jsonPath)
4441

4542
if (existing) {
@@ -83,7 +80,6 @@ function read(jsonPath, {base, specifier}) {
8380
(base ? `"${specifier}" from ` : '') + fileURLToPath(base || specifier),
8481
cause.message
8582
)
86-
// @ts-expect-error: fine.
8783
error.cause = cause
8884
throw error
8985
}
@@ -127,3 +123,55 @@ function read(jsonPath, {base, specifier}) {
127123

128124
return result
129125
}
126+
127+
/**
128+
* @param {URL | string} resolved
129+
* @returns {PackageConfig}
130+
*/
131+
export function getPackageScopeConfig(resolved) {
132+
// Note: in Node, this is now a native module.
133+
let packageJSONUrl = new URL('package.json', resolved)
134+
135+
while (true) {
136+
const packageJSONPath = packageJSONUrl.pathname
137+
if (packageJSONPath.endsWith('node_modules/package.json')) {
138+
break
139+
}
140+
141+
const packageConfig = read(fileURLToPath(packageJSONUrl), {
142+
specifier: resolved
143+
})
144+
145+
if (packageConfig.exists) {
146+
return packageConfig
147+
}
148+
149+
const lastPackageJSONUrl = packageJSONUrl
150+
packageJSONUrl = new URL('../package.json', packageJSONUrl)
151+
152+
// Terminates at root where ../package.json equals ../../package.json
153+
// (can't just check "/package.json" for Windows support).
154+
if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) {
155+
break
156+
}
157+
}
158+
159+
const packageJSONPath = fileURLToPath(packageJSONUrl)
160+
// ^^ Note: in Node, this is now a native module.
161+
162+
return {
163+
pjsonPath: packageJSONPath,
164+
exists: false,
165+
type: 'none'
166+
}
167+
}
168+
169+
/**
170+
* Returns the package type for a given URL.
171+
* @param {URL} url - The URL to get the package type for.
172+
* @returns {PackageType}
173+
*/
174+
export function getPackageType(url) {
175+
// To do @anonrig: Write a C++ function that returns only "type".
176+
return getPackageScopeConfig(url).type
177+
}

lib/resolve-get-package-type.js

Lines changed: 0 additions & 23 deletions
This file was deleted.

lib/resolve.js

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// Manually “tree shaken” from:
2-
// <https://github.com/nodejs/node/blob/45f5c9b/lib/internal/modules/esm/resolve.js>
3-
// Last checked on: Nov 2, 2023.
2+
// <https://github.com/nodejs/node/blob/81a9a97/lib/internal/modules/esm/resolve.js>
3+
// Last checked on: Apr 29, 2023.
44

55
/**
66
* @typedef {import('./errors.js').ErrnoException} ErrnoException
7-
* @typedef {import('./package-config.js').PackageConfig} PackageConfig
7+
* @typedef {import('./package-json-reader.js').PackageConfig} PackageConfig
88
*/
99

1010
import assert from 'node:assert'
@@ -15,8 +15,7 @@ import path from 'node:path'
1515
import {builtinModules} from 'node:module'
1616
import {defaultGetFormatWithoutErrors} from './get-format.js'
1717
import {codes} from './errors.js'
18-
import {getPackageScopeConfig} from './package-config.js'
19-
import packageJsonReader from './package-json-reader.js'
18+
import {getPackageScopeConfig, read} from './package-json-reader.js'
2019
import {getConditionsSet} from './utils.js'
2120

2221
const RegExpPrototypeSymbolReplace = RegExp.prototype[Symbol.replace]
@@ -29,7 +28,8 @@ const {
2928
ERR_MODULE_NOT_FOUND,
3029
ERR_PACKAGE_IMPORT_NOT_DEFINED,
3130
ERR_PACKAGE_PATH_NOT_EXPORTED,
32-
ERR_UNSUPPORTED_DIR_IMPORT
31+
ERR_UNSUPPORTED_DIR_IMPORT,
32+
ERR_UNSUPPORTED_RESOLVE_REQUEST
3333
} = codes
3434

3535
const own = {}.hasOwnProperty
@@ -909,10 +909,6 @@ function packageImportsResolve(name, base, conditions) {
909909
throw importNotDefined(name, packageJsonUrl, base)
910910
}
911911

912-
// Note: In Node.js, `getPackageType` is here.
913-
// To prevent a circular dependency, we move it to
914-
// `resolve-get-package-type.js`.
915-
916912
/**
917913
* @param {string} specifier
918914
* @param {URL} base
@@ -1013,10 +1009,7 @@ function packageResolve(specifier, base, conditions) {
10131009
}
10141010

10151011
// Package match.
1016-
const packageConfig = packageJsonReader.read(packageJsonPath, {
1017-
base,
1018-
specifier
1019-
})
1012+
const packageConfig = read(packageJsonPath, {base, specifier})
10201013
if (packageConfig.exports !== undefined && packageConfig.exports !== null) {
10211014
return packageExportsResolve(
10221015
packageJsonUrl,
@@ -1082,24 +1075,38 @@ function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) {
10821075
* A URL object to the found thing.
10831076
*/
10841077
export function moduleResolve(specifier, base, conditions, preserveSymlinks) {
1078+
// Note: The Node code supports `base` as a string (in this internal API) too,
1079+
// we don’t.
10851080
const protocol = base.protocol
1086-
const isRemote = protocol === 'http:' || protocol === 'https:'
1081+
const isData = protocol === 'data:'
1082+
const isRemote = isData || protocol === 'http:' || protocol === 'https:'
10871083
// Order swapped from spec for minor perf gain.
10881084
// Ok since relative URLs cannot parse as URLs.
10891085
/** @type {URL | undefined} */
10901086
let resolved
10911087

10921088
if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
1093-
resolved = new URL(specifier, base)
1094-
} else if (!isRemote && specifier[0] === '#') {
1089+
try {
1090+
resolved = new URL(specifier, base)
1091+
} catch (error_) {
1092+
const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base)
1093+
error.cause = error_
1094+
throw error
1095+
}
1096+
} else if (protocol === 'file:' && specifier[0] === '#') {
10951097
resolved = packageImportsResolve(specifier, base, conditions)
10961098
} else {
10971099
try {
10981100
resolved = new URL(specifier)
1099-
} catch {
1100-
if (!isRemote) {
1101-
resolved = packageResolve(specifier, base, conditions)
1101+
} catch (error_) {
1102+
// Note: actual code uses `canBeRequiredWithoutScheme`.
1103+
if (isRemote && !builtinModules.includes(specifier)) {
1104+
const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base)
1105+
error.cause = error_
1106+
throw error
11021107
}
1108+
1109+
resolved = packageResolve(specifier, base, conditions)
11031110
}
11041111
}
11051112

@@ -1232,13 +1239,16 @@ export function defaultResolve(specifier, context = {}) {
12321239

12331240
/** @type {URL | undefined} */
12341241
let parsed
1242+
/** @type {string | undefined} */
1243+
let protocol
1244+
12351245
try {
12361246
parsed = shouldBeTreatedAsRelativeOrAbsolutePath(specifier)
12371247
? new URL(specifier, parsedParentURL)
12381248
: new URL(specifier)
12391249

12401250
// Avoid accessing the `protocol` property due to the lazy getters.
1241-
const protocol = parsed.protocol
1251+
protocol = parsed.protocol
12421252

12431253
if (protocol === 'data:') {
12441254
return {url: parsed.href, format: null}
@@ -1258,6 +1268,15 @@ export function defaultResolve(specifier, context = {}) {
12581268

12591269
if (maybeReturn) return maybeReturn
12601270

1271+
// This must come after checkIfDisallowedImport
1272+
if (protocol === undefined && parsed) {
1273+
protocol = parsed.protocol
1274+
}
1275+
1276+
if (protocol === 'node:') {
1277+
return {url: specifier}
1278+
}
1279+
12611280
// This must come after checkIfDisallowedImport
12621281
if (parsed && parsed.protocol === 'node:') return {url: specifier}
12631282

lib/utils.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Manually “tree shaken” from:
2-
// <https://github.com/nodejs/node/blob/45f5c9b/lib/internal/modules/esm/utils.js>
3-
// Last checked on: Nov 2, 2023.
2+
// <https://github.com/nodejs/node/blob/81a9a97/lib/internal/modules/esm/utils.js>
3+
// Last checked on: Apr 29, 2023.
44

55
import {codes} from './errors.js'
66

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"emitDeclarationOnly": true,
88
"exactOptionalPropertyTypes": true,
99
"forceConsistentCasingInFileNames": true,
10-
"lib": ["es2020"],
10+
"lib": ["es2022"],
1111
"module": "node16",
1212
"newLine": "lf",
1313
"strict": true,

0 commit comments

Comments
 (0)