node/lib/internal/modules/package_json_reader.js
Rafael Gonzaga 951af83033
lib,src: remove --experimental-policy
Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com>
PR-URL: https://github.com/nodejs/node/pull/52583
Refs: https://github.com/nodejs/node/issues/52575
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
2024-05-07 16:25:45 +00:00

164 lines
4.7 KiB
JavaScript

'use strict';
const {
ArrayIsArray,
JSONParse,
ObjectDefineProperty,
StringPrototypeLastIndexOf,
StringPrototypeSlice,
} = primordials;
const modulesBinding = internalBinding('modules');
const { resolve, sep } = require('path');
const { kEmptyObject } = require('internal/util');
/**
* @param {string} path
* @param {import('typings/internalBinding/modules').SerializedPackageConfig} contents
* @returns {import('typings/internalBinding/modules').PackageConfig}
*/
function deserializePackageJSON(path, contents) {
if (contents === undefined) {
return {
__proto__: null,
exists: false,
pjsonPath: path,
type: 'none', // Ignore unknown types for forwards compatibility
};
}
let pjsonPath = path;
const {
0: name,
1: main,
2: type,
3: plainImports,
4: plainExports,
5: optionalFilePath,
} = contents;
// This is required to be used in getPackageScopeConfig.
if (optionalFilePath) {
pjsonPath = optionalFilePath;
}
// The imports and exports fields can be either undefined or a string.
// - If it's a string, it's either plain string or a stringified JSON string.
// - If it's a stringified JSON string, it starts with either '[' or '{'.
const requiresJSONParse = (value) => (value !== undefined && (value[0] === '[' || value[0] === '{'));
return {
__proto__: null,
exists: true,
pjsonPath,
name,
main,
type,
// This getters are used to lazily parse the imports and exports fields.
get imports() {
const value = requiresJSONParse(plainImports) ? JSONParse(plainImports) : plainImports;
ObjectDefineProperty(this, 'imports', { __proto__: null, value });
return this.imports;
},
get exports() {
const value = requiresJSONParse(plainExports) ? JSONParse(plainExports) : plainExports;
ObjectDefineProperty(this, 'exports', { __proto__: null, value });
return this.exports;
},
};
}
/**
* Reads a package.json file and returns the parsed contents.
* @param {string} jsonPath
* @param {{
* base?: URL | string,
* specifier?: URL | string,
* isESM?: boolean,
* }} options
* @returns {import('typings/internalBinding/modules').PackageConfig}
*/
function read(jsonPath, { base, specifier, isESM } = kEmptyObject) {
// This function will be called by both CJS and ESM, so we need to make sure
// non-null attributes are converted to strings.
const parsed = modulesBinding.readPackageJSON(
jsonPath,
isESM,
base == null ? undefined : `${base}`,
specifier == null ? undefined : `${specifier}`,
);
return deserializePackageJSON(jsonPath, parsed);
}
/**
* @deprecated Expected to be removed in favor of `read` in the future.
* Behaves the same was as `read`, but appends package.json to the path.
* @param {string} requestPath
* @return {PackageConfig}
*/
function readPackage(requestPath) {
// TODO(@anonrig): Remove this function.
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 undefined.
* @param {string} checkPath The path to start searching from.
* @returns {undefined | {data: import('typings/internalBinding/modules').PackageConfig, path: string}}
*/
function getNearestParentPackageJSON(checkPath) {
const result = modulesBinding.getNearestParentPackageJSON(checkPath);
if (result === undefined) {
return undefined;
}
const data = deserializePackageJSON(checkPath, result);
// Path should be the root folder of the matched package.json
// For example for ~/path/package.json, it should be ~/path
const path = StringPrototypeSlice(data.pjsonPath, 0, StringPrototypeLastIndexOf(data.pjsonPath, sep));
return { data, path };
}
/**
* Returns the package configuration for the given resolved URL.
* @param {URL | string} resolved - The resolved URL.
* @returns {import('typings/internalBinding/modules').PackageConfig} - The package configuration.
*/
function getPackageScopeConfig(resolved) {
const result = modulesBinding.getPackageScopeConfig(`${resolved}`);
if (ArrayIsArray(result)) {
return deserializePackageJSON(`${resolved}`, result);
}
// This means that the response is a string
// and it is the path to the package.json file
return {
__proto__: null,
pjsonPath: result,
exists: false,
type: 'none',
};
}
/**
* Returns the package type for a given URL.
* @param {URL} url - The URL to get the package type for.
*/
function getPackageType(url) {
// TODO(@anonrig): Write a C++ function that returns only "type".
return getPackageScopeConfig(url).type;
}
module.exports = {
read,
readPackage,
getNearestParentPackageJSON,
getPackageScopeConfig,
getPackageType,
};