2020-05-04 12:50:42 +03:00
|
|
|
'use strict';
|
|
|
|
|
2023-06-29 14:45:31 -04:00
|
|
|
const {
|
|
|
|
JSONParse,
|
|
|
|
ObjectPrototypeHasOwnProperty,
|
|
|
|
SafeMap,
|
|
|
|
} = primordials;
|
|
|
|
const {
|
|
|
|
ERR_INVALID_PACKAGE_CONFIG,
|
|
|
|
} = require('internal/errors').codes;
|
2020-05-04 12:50:42 +03:00
|
|
|
const { internalModuleReadJSON } = internalBinding('fs');
|
2020-07-16 16:00:21 -05:00
|
|
|
const { toNamespacedPath } = require('path');
|
2023-06-29 14:45:31 -04:00
|
|
|
const { kEmptyObject } = require('internal/util');
|
|
|
|
|
|
|
|
const { fileURLToPath, pathToFileURL } = require('internal/url');
|
2020-05-04 12:50:42 +03:00
|
|
|
|
|
|
|
const cache = new SafeMap();
|
2023-06-29 14:45:31 -04:00
|
|
|
const isAIX = process.platform === 'aix';
|
2020-05-04 12:50:42 +03:00
|
|
|
|
2020-07-17 11:38:46 -05:00
|
|
|
let manifest;
|
|
|
|
|
2020-05-04 12:50:42 +03:00
|
|
|
/**
|
2023-06-29 14:45:31 -04:00
|
|
|
* @typedef {{
|
|
|
|
* exists: boolean,
|
|
|
|
* pjsonPath: string,
|
|
|
|
* exports?: string | string[] | Record<string, unknown>,
|
|
|
|
* imports?: string | string[] | Record<string, unknown>,
|
|
|
|
* name?: string,
|
|
|
|
* main?: string,
|
|
|
|
* type: 'commonjs' | 'module' | 'none',
|
|
|
|
* }} PackageConfig
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2020-07-16 16:00:21 -05:00
|
|
|
* @param {string} jsonPath
|
2023-06-29 14:45:31 -04:00
|
|
|
* @param {{
|
|
|
|
* base?: string,
|
|
|
|
* specifier: string,
|
|
|
|
* isESM: boolean,
|
|
|
|
* }} options
|
|
|
|
* @returns {PackageConfig}
|
2020-05-04 12:50:42 +03:00
|
|
|
*/
|
2023-06-29 14:45:31 -04:00
|
|
|
function read(jsonPath, { base, specifier, isESM } = kEmptyObject) {
|
2020-07-16 16:00:21 -05:00
|
|
|
if (cache.has(jsonPath)) {
|
|
|
|
return cache.get(jsonPath);
|
2020-05-04 12:50:42 +03:00
|
|
|
}
|
|
|
|
|
2023-06-29 14:45:31 -04:00
|
|
|
const {
|
|
|
|
0: string,
|
|
|
|
1: containsKeys,
|
|
|
|
} = internalModuleReadJSON(
|
2023-02-14 18:45:16 +01:00
|
|
|
toNamespacedPath(jsonPath),
|
2020-07-16 16:00:21 -05:00
|
|
|
);
|
2023-06-29 14:45:31 -04:00
|
|
|
const result = {
|
|
|
|
__proto__: null,
|
|
|
|
exists: false,
|
|
|
|
pjsonPath: jsonPath,
|
|
|
|
main: undefined,
|
|
|
|
name: undefined,
|
|
|
|
type: 'none', // Ignore unknown types for forwards compatibility
|
|
|
|
exports: undefined,
|
|
|
|
imports: undefined,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Folder read operation succeeds in AIX.
|
|
|
|
// For libuv change, see https://github.com/libuv/libuv/pull/2025.
|
|
|
|
// https://github.com/nodejs/node/pull/48477#issuecomment-1604586650
|
|
|
|
// TODO(anonrig): Follow-up on this change and remove it since it is a
|
|
|
|
// semver-major change.
|
|
|
|
const isResultValid = isAIX && !isESM ? containsKeys : string !== undefined;
|
|
|
|
|
|
|
|
if (isResultValid) {
|
|
|
|
let parsed;
|
|
|
|
try {
|
|
|
|
parsed = JSONParse(string);
|
|
|
|
} catch (error) {
|
|
|
|
if (isESM) {
|
|
|
|
throw new ERR_INVALID_PACKAGE_CONFIG(
|
|
|
|
jsonPath,
|
|
|
|
(base ? `"${specifier}" from ` : '') + fileURLToPath(base || specifier),
|
|
|
|
error.message,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// For backward compat, we modify the error returned by JSON.parse rather than creating a new one.
|
|
|
|
// TODO(aduh95): make it throw ERR_INVALID_PACKAGE_CONFIG in a semver-major with original error as cause
|
|
|
|
error.message = 'Error parsing ' + jsonPath + ': ' + error.message;
|
|
|
|
error.path = jsonPath;
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result.exists = true;
|
|
|
|
|
|
|
|
// ObjectPrototypeHasOwnProperty is used to avoid prototype pollution.
|
|
|
|
if (ObjectPrototypeHasOwnProperty(parsed, 'name') && typeof parsed.name === 'string') {
|
|
|
|
result.name = parsed.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ObjectPrototypeHasOwnProperty(parsed, 'main') && typeof parsed.main === 'string') {
|
|
|
|
result.main = parsed.main;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ObjectPrototypeHasOwnProperty(parsed, 'exports')) {
|
|
|
|
result.exports = parsed.exports;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ObjectPrototypeHasOwnProperty(parsed, 'imports')) {
|
|
|
|
result.imports = parsed.imports;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignore unknown types for forwards compatibility
|
|
|
|
if (ObjectPrototypeHasOwnProperty(parsed, 'type') && (parsed.type === 'commonjs' || parsed.type === 'module')) {
|
|
|
|
result.type = parsed.type;
|
|
|
|
}
|
|
|
|
|
2020-07-17 11:38:46 -05:00
|
|
|
if (manifest === undefined) {
|
2023-06-29 14:45:31 -04:00
|
|
|
const { getOptionValue } = require('internal/options');
|
2020-07-17 11:38:46 -05:00
|
|
|
manifest = getOptionValue('--experimental-policy') ?
|
|
|
|
require('internal/process/policy').manifest :
|
|
|
|
null;
|
|
|
|
}
|
|
|
|
if (manifest !== null) {
|
2020-07-16 16:00:21 -05:00
|
|
|
const jsonURL = pathToFileURL(jsonPath);
|
|
|
|
manifest.assertIntegrity(jsonURL, string);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cache.set(jsonPath, result);
|
2020-05-04 12:50:42 +03:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = { read };
|