From eaf841d585f431e5f2fea6490bb6ff4ae9e74f10 Mon Sep 17 00:00:00 2001 From: Myles Borins Date: Fri, 17 Apr 2020 17:13:16 -0400 Subject: [PATCH] module: improve error for invalid package targets For targets that are strings that do not start with `./` or `/` the error will now have additional information about what the programming error is. Closes: https://github.com/nodejs/node/issues/32034 PR-URL: https://github.com/nodejs/node/pull/32052 Fixes: https://github.com/nodejs/node/issues/32034 Reviewed-By: Geoffrey Booth Reviewed-By: Ruben Bridgewater Reviewed-By: Jan Krems Reviewed-By: Guy Bedford Signed-off-by: Myles Borins --- lib/internal/errors.js | 17 ++++++++++++++--- test/es-module/test-esm-exports.mjs | 4 ++++ .../node_modules/pkgexports/package.json | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/internal/errors.js b/lib/internal/errors.js index e0668e2f827e5f..6fa230349072d6 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -20,6 +20,7 @@ const { ObjectDefineProperty, ObjectKeys, StringPrototypeSlice, + StringPrototypeStartsWith, Symbol, SymbolFor, WeakMap, @@ -1104,18 +1105,28 @@ E('ERR_INVALID_PACKAGE_CONFIG', (path, message, hasMessage = true) => { }, Error); E('ERR_INVALID_PACKAGE_TARGET', (pkgPath, key, subpath, target, base = undefined) => { + const relError = typeof target === 'string' && + target.length && !StringPrototypeStartsWith(target, './'); if (key === null) { if (subpath !== '') { return `Invalid "exports" target ${JSONStringify(target)} defined ` + `for '${subpath}' in the package config ${pkgPath} imported from ` + - base; + `${base}.${relError ? '; targets must start with "./"' : ''}`; } else { return `Invalid "exports" main target ${target} defined in the ` + - `package config ${pkgPath} imported from ${base}.`; + `package config ${pkgPath} imported from ${base}${relError ? + '; targets must start with "./"' : ''}`; } } else if (key === '.') { return `Invalid "exports" main target ${JSONStringify(target)} defined ` + - `in the package config ${pkgPath}${sep}package.json`; + `in the package config ${pkgPath}${sep}package.json${relError ? + '; targets must start with "./"' : ''}`; + } else if (typeof target === 'string' && target !== '' && + !StringPrototypeStartsWith(target, './')) { + return `Invalid "exports" target ${JSONStringify(target)} defined for '${ + StringPrototypeSlice(key, 0, -subpath.length || key.length)}' in the ` + + `package config ${pkgPath}${sep}package.json; ` + + 'targets must start with "./"'; } else { return `Invalid "exports" target ${JSONStringify(target)} defined for '${ StringPrototypeSlice(key, 0, -subpath.length || key.length)}' in the ` + diff --git a/test/es-module/test-esm-exports.mjs b/test/es-module/test-esm-exports.mjs index f71e2172951843..2b58f28344522c 100644 --- a/test/es-module/test-esm-exports.mjs +++ b/test/es-module/test-esm-exports.mjs @@ -78,6 +78,7 @@ import fromInside from '../fixtures/node_modules/pkgexports/lib/hole.js'; ['pkgexports/null', './null'], ['pkgexports/invalid2', './invalid2'], ['pkgexports/invalid3', './invalid3'], + ['pkgexports/invalid5', 'invalid5'], // Missing / invalid fallbacks ['pkgexports/nofallback1', './nofallback1'], ['pkgexports/nofallback2', './nofallback2'], @@ -106,6 +107,9 @@ import fromInside from '../fixtures/node_modules/pkgexports/lib/hole.js'; strictEqual(err.code, 'ERR_INVALID_PACKAGE_TARGET'); assertStartsWith(err.message, 'Invalid "exports"'); assertIncludes(err.message, subpath); + if (!subpath.startsWith('./')) { + assertIncludes(err.message, 'targets must start with'); + } })); } diff --git a/test/fixtures/node_modules/pkgexports/package.json b/test/fixtures/node_modules/pkgexports/package.json index f3ec20c49b2b91..43ccf7795b978e 100644 --- a/test/fixtures/node_modules/pkgexports/package.json +++ b/test/fixtures/node_modules/pkgexports/package.json @@ -13,6 +13,7 @@ "./invalid2": 1234, "./invalid3": "", "./invalid4": {}, + "./invalid5": "invalid5.js", "./fallbackdir/": [[], null, {}, "builtin:x/", "./fallbackfile", "./"], "./fallbackfile": [[], null, {}, "builtin:x", "./asdf.js"], "./nofallback1": [],