Skip to content

Commit

Permalink
readPackage and readPackageScope
Browse files Browse the repository at this point in the history
  • Loading branch information
GeoffreyBooth committed Sep 29, 2023
1 parent ed3ca73 commit 3ea0b32
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 49 deletions.
51 changes: 5 additions & 46 deletions lib/internal/modules/cjs/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ const {
StringPrototypeCharAt,
StringPrototypeCharCodeAt,
StringPrototypeEndsWith,
StringPrototypeLastIndexOf,
StringPrototypeIndexOf,
StringPrototypeRepeat,
StringPrototypeSlice,
Expand All @@ -68,7 +67,7 @@ const cjsParseCache = new SafeWeakMap();

// Set first due to cycle with ESM loader functions.
module.exports = {
wrapSafe, Module, readPackageScope, cjsParseCache,
wrapSafe, Module, cjsParseCache,
get hasLoadedAnyUserCJSModule() { return hasLoadedAnyUserCJSModule; },
initializeCJS,
};
Expand All @@ -89,7 +88,6 @@ const { internalCompileFunction } = require('internal/vm');
const assert = require('internal/assert');
const fs = require('fs');
const path = require('path');
const { sep } = path;
const { internalModuleStat } = internalBinding('fs');
const { safeGetenv } = internalBinding('credentials');
const {
Expand Down Expand Up @@ -403,15 +401,7 @@ function initializeCJS() {
// -> a.<ext>
// -> a/index.<ext>

/**
* @param {string} requestPath
* @return {PackageConfig}
*/
function readPackage(requestPath) {
return packageJsonReader.read(path.resolve(requestPath, 'package.json'));
}

let _readPackage = readPackage;
let _readPackage = packageJsonReader.readPackage;
ObjectDefineProperty(Module, '_readPackage', {
__proto__: null,
get() { return _readPackage; },
Expand All @@ -423,37 +413,6 @@ ObjectDefineProperty(Module, '_readPackage', {
configurable: true,
});

/**
* Get the nearest parent package.json file from a given path.
* Return the package.json data and the path to the package.json file, or false.
* @param {string} checkPath The path to start searching from.
*/
function readPackageScope(checkPath) {
const rootSeparatorIndex = StringPrototypeIndexOf(checkPath, sep);
let separatorIndex;
const enabledPermission = permission.isEnabled();
do {
separatorIndex = StringPrototypeLastIndexOf(checkPath, sep);
checkPath = StringPrototypeSlice(checkPath, 0, separatorIndex);
// Stop the search when the process doesn't have permissions
// to walk upwards
if (enabledPermission && !permission.has('fs.read', checkPath + sep)) {
return false;
}
if (StringPrototypeEndsWith(checkPath, sep + 'node_modules')) {
return false;
}
const pjson = _readPackage(checkPath + sep);
if (pjson.exists) {
return {
data: pjson,
path: checkPath,
};
}
} while (separatorIndex > rootSeparatorIndex);
return false;
}

/**
* Try to load a specifier as a package.
* @param {string} requestPath The path to what we are trying to load
Expand Down Expand Up @@ -574,7 +533,7 @@ function trySelfParentPath(parent) {
function trySelf(parentPath, request) {
if (!parentPath) { return false; }

const { data: pkg, path: pkgPath } = readPackageScope(parentPath);
const { data: pkg, path: pkgPath } = packageJsonReader.readPackageScope(parentPath);
if (!pkg || pkg.exports == null || pkg.name === undefined) {
return false;
}
Expand Down Expand Up @@ -1134,7 +1093,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {

if (request[0] === '#' && (parent?.filename || parent?.id === '<repl>')) {
const parentPath = parent?.filename ?? process.cwd() + path.sep;
const pkg = readPackageScope(parentPath) || { __proto__: null };
const pkg = packageJsonReader.readPackageScope(parentPath) || { __proto__: null };
if (pkg.data?.imports != null) {
try {
const { packageImportsResolve } = require('internal/modules/esm/resolve');
Expand Down Expand Up @@ -1431,7 +1390,7 @@ Module._extensions['.js'] = function(module, filename) {
content = fs.readFileSync(filename, 'utf8');
}
if (StringPrototypeEndsWith(filename, '.js')) {
const pkg = readPackageScope(filename) || { __proto__: null };
const pkg = packageJsonReader.readPackageScope(filename) || { __proto__: null };
// Function require shouldn't be used in ES modules.
if (pkg.data?.type === 'module') {
const parent = moduleParentCache.get(module);
Expand Down
52 changes: 50 additions & 2 deletions lib/internal/modules/package_json_reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@ const {
JSONParse,
ObjectPrototypeHasOwnProperty,
SafeMap,
StringPrototypeEndsWith,
StringPrototypeIndexOf,
StringPrototypeLastIndexOf,
StringPrototypeSlice,
} = primordials;
const {
ERR_INVALID_PACKAGE_CONFIG,
} = require('internal/errors').codes;
const { internalModuleReadJSON } = internalBinding('fs');
const { toNamespacedPath } = require('path');
const { resolve, sep, toNamespacedPath } = require('path');
const permission = require('internal/process/permission');
const { kEmptyObject, setOwnProperty } = require('internal/util');

const { fileURLToPath, pathToFileURL } = require('internal/url');
Expand Down Expand Up @@ -111,4 +116,47 @@ function read(jsonPath, { base, specifier, isESM } = kEmptyObject) {
return result;
}

module.exports = { read };
/**
* @param {string} requestPath
* @return {PackageConfig}
*/
function readPackage(requestPath) {
return read(resolve(requestPath, 'package.json'));
}

/**
* Get the nearest parent package.json file from a given path.
* Return the package.json data and the path to the package.json file, or false.
* @param {string} checkPath The path to start searching from.
*/
function readPackageScope(checkPath) {
const rootSeparatorIndex = StringPrototypeIndexOf(checkPath, sep);
let separatorIndex;
const enabledPermission = permission.isEnabled();
do {
separatorIndex = StringPrototypeLastIndexOf(checkPath, sep);
checkPath = StringPrototypeSlice(checkPath, 0, separatorIndex);
// Stop the search when the process doesn't have permissions
// to walk upwards
if (enabledPermission && !permission.has('fs.read', checkPath + sep)) {
return false;
}
if (StringPrototypeEndsWith(checkPath, sep + 'node_modules')) {
return false;
}
const pjson = readPackage(checkPath + sep);
if (pjson.exists) {
return {
data: pjson,
path: checkPath,
};
}
} while (separatorIndex > rootSeparatorIndex);
return false;
}

module.exports = {
read,
readPackage,
readPackageScope,
};
2 changes: 1 addition & 1 deletion lib/internal/modules/run_main.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function shouldUseESMLoader(mainPath) {
if (mainPath && StringPrototypeEndsWith(mainPath, '.mjs')) { return true; }
if (!mainPath || StringPrototypeEndsWith(mainPath, '.cjs')) { return false; }

const { readPackageScope } = require('internal/modules/cjs/loader');
const { readPackageScope } = require('internal/modules/package_json_reader');
const pkg = readPackageScope(mainPath);
// No need to guard `pkg` as it can only be an object or `false`.
return pkg.data?.type === 'module' || getOptionValue('--experimental-default-type') === 'module';
Expand Down

0 comments on commit 3ea0b32

Please sign in to comment.