11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst {
41cb0ef41Sopenharmony_ci  JSONParse,
51cb0ef41Sopenharmony_ci  ObjectPrototypeHasOwnProperty,
61cb0ef41Sopenharmony_ci  SafeMap,
71cb0ef41Sopenharmony_ci  StringPrototypeEndsWith,
81cb0ef41Sopenharmony_ci  StringPrototypeIndexOf,
91cb0ef41Sopenharmony_ci  StringPrototypeLastIndexOf,
101cb0ef41Sopenharmony_ci  StringPrototypeSlice,
111cb0ef41Sopenharmony_ci} = primordials;
121cb0ef41Sopenharmony_ciconst {
131cb0ef41Sopenharmony_ci  ERR_INVALID_PACKAGE_CONFIG,
141cb0ef41Sopenharmony_ci} = require('internal/errors').codes;
151cb0ef41Sopenharmony_ciconst { internalModuleReadJSON } = internalBinding('fs');
161cb0ef41Sopenharmony_ciconst { resolve, sep, toNamespacedPath } = require('path');
171cb0ef41Sopenharmony_ciconst { kEmptyObject } = require('internal/util');
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ciconst { fileURLToPath, pathToFileURL } = require('internal/url');
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ciconst cache = new SafeMap();
221cb0ef41Sopenharmony_ciconst isAIX = process.platform === 'aix';
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_cilet manifest;
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci/**
271cb0ef41Sopenharmony_ci * @typedef {{
281cb0ef41Sopenharmony_ci *   exists: boolean,
291cb0ef41Sopenharmony_ci *   pjsonPath: string,
301cb0ef41Sopenharmony_ci *   exports?: string | string[] | Record<string, unknown>,
311cb0ef41Sopenharmony_ci *   imports?: string | string[] | Record<string, unknown>,
321cb0ef41Sopenharmony_ci *   name?: string,
331cb0ef41Sopenharmony_ci *   main?: string,
341cb0ef41Sopenharmony_ci *   type: 'commonjs' | 'module' | 'none',
351cb0ef41Sopenharmony_ci * }} PackageConfig
361cb0ef41Sopenharmony_ci */
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci/**
391cb0ef41Sopenharmony_ci * @param {string} jsonPath
401cb0ef41Sopenharmony_ci * @param {{
411cb0ef41Sopenharmony_ci *   base?: string,
421cb0ef41Sopenharmony_ci *   specifier: string,
431cb0ef41Sopenharmony_ci *   isESM: boolean,
441cb0ef41Sopenharmony_ci * }} options
451cb0ef41Sopenharmony_ci * @returns {PackageConfig}
461cb0ef41Sopenharmony_ci */
471cb0ef41Sopenharmony_cifunction read(jsonPath, { base, specifier, isESM } = kEmptyObject) {
481cb0ef41Sopenharmony_ci  if (cache.has(jsonPath)) {
491cb0ef41Sopenharmony_ci    return cache.get(jsonPath);
501cb0ef41Sopenharmony_ci  }
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci  const {
531cb0ef41Sopenharmony_ci    0: string,
541cb0ef41Sopenharmony_ci    1: containsKeys,
551cb0ef41Sopenharmony_ci  } = internalModuleReadJSON(
561cb0ef41Sopenharmony_ci    toNamespacedPath(jsonPath),
571cb0ef41Sopenharmony_ci  );
581cb0ef41Sopenharmony_ci  const result = {
591cb0ef41Sopenharmony_ci    __proto__: null,
601cb0ef41Sopenharmony_ci    exists: false,
611cb0ef41Sopenharmony_ci    pjsonPath: jsonPath,
621cb0ef41Sopenharmony_ci    main: undefined,
631cb0ef41Sopenharmony_ci    name: undefined,
641cb0ef41Sopenharmony_ci    type: 'none', // Ignore unknown types for forwards compatibility
651cb0ef41Sopenharmony_ci    exports: undefined,
661cb0ef41Sopenharmony_ci    imports: undefined,
671cb0ef41Sopenharmony_ci  };
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci  // Folder read operation succeeds in AIX.
701cb0ef41Sopenharmony_ci  // For libuv change, see https://github.com/libuv/libuv/pull/2025.
711cb0ef41Sopenharmony_ci  // https://github.com/nodejs/node/pull/48477#issuecomment-1604586650
721cb0ef41Sopenharmony_ci  // TODO(anonrig): Follow-up on this change and remove it since it is a
731cb0ef41Sopenharmony_ci  // semver-major change.
741cb0ef41Sopenharmony_ci  const isResultValid = isAIX && !isESM ? containsKeys : string !== undefined;
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci  if (isResultValid) {
771cb0ef41Sopenharmony_ci    let parsed;
781cb0ef41Sopenharmony_ci    try {
791cb0ef41Sopenharmony_ci      parsed = JSONParse(string);
801cb0ef41Sopenharmony_ci    } catch (error) {
811cb0ef41Sopenharmony_ci      if (isESM) {
821cb0ef41Sopenharmony_ci        throw new ERR_INVALID_PACKAGE_CONFIG(
831cb0ef41Sopenharmony_ci          jsonPath,
841cb0ef41Sopenharmony_ci          (base ? `"${specifier}" from ` : '') + fileURLToPath(base || specifier),
851cb0ef41Sopenharmony_ci          error.message,
861cb0ef41Sopenharmony_ci        );
871cb0ef41Sopenharmony_ci      } else {
881cb0ef41Sopenharmony_ci        // For backward compat, we modify the error returned by JSON.parse rather than creating a new one.
891cb0ef41Sopenharmony_ci        // TODO(aduh95): make it throw ERR_INVALID_PACKAGE_CONFIG in a semver-major with original error as cause
901cb0ef41Sopenharmony_ci        error.message = 'Error parsing ' + jsonPath + ': ' + error.message;
911cb0ef41Sopenharmony_ci        error.path = jsonPath;
921cb0ef41Sopenharmony_ci        throw error;
931cb0ef41Sopenharmony_ci      }
941cb0ef41Sopenharmony_ci    }
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci    result.exists = true;
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci    // ObjectPrototypeHasOwnProperty is used to avoid prototype pollution.
991cb0ef41Sopenharmony_ci    if (ObjectPrototypeHasOwnProperty(parsed, 'name') && typeof parsed.name === 'string') {
1001cb0ef41Sopenharmony_ci      result.name = parsed.name;
1011cb0ef41Sopenharmony_ci    }
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci    if (ObjectPrototypeHasOwnProperty(parsed, 'main') && typeof parsed.main === 'string') {
1041cb0ef41Sopenharmony_ci      result.main = parsed.main;
1051cb0ef41Sopenharmony_ci    }
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ci    if (ObjectPrototypeHasOwnProperty(parsed, 'exports')) {
1081cb0ef41Sopenharmony_ci      result.exports = parsed.exports;
1091cb0ef41Sopenharmony_ci    }
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci    if (ObjectPrototypeHasOwnProperty(parsed, 'imports')) {
1121cb0ef41Sopenharmony_ci      result.imports = parsed.imports;
1131cb0ef41Sopenharmony_ci    }
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci    // Ignore unknown types for forwards compatibility
1161cb0ef41Sopenharmony_ci    if (ObjectPrototypeHasOwnProperty(parsed, 'type') && (parsed.type === 'commonjs' || parsed.type === 'module')) {
1171cb0ef41Sopenharmony_ci      result.type = parsed.type;
1181cb0ef41Sopenharmony_ci    }
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci    if (manifest === undefined) {
1211cb0ef41Sopenharmony_ci      const { getOptionValue } = require('internal/options');
1221cb0ef41Sopenharmony_ci      manifest = getOptionValue('--experimental-policy') ?
1231cb0ef41Sopenharmony_ci        require('internal/process/policy').manifest :
1241cb0ef41Sopenharmony_ci        null;
1251cb0ef41Sopenharmony_ci    }
1261cb0ef41Sopenharmony_ci    if (manifest !== null) {
1271cb0ef41Sopenharmony_ci      const jsonURL = pathToFileURL(jsonPath);
1281cb0ef41Sopenharmony_ci      manifest.assertIntegrity(jsonURL, string);
1291cb0ef41Sopenharmony_ci    }
1301cb0ef41Sopenharmony_ci  }
1311cb0ef41Sopenharmony_ci  cache.set(jsonPath, result);
1321cb0ef41Sopenharmony_ci  return result;
1331cb0ef41Sopenharmony_ci}
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci/**
1361cb0ef41Sopenharmony_ci * @param {string} requestPath
1371cb0ef41Sopenharmony_ci * @return {PackageConfig}
1381cb0ef41Sopenharmony_ci */
1391cb0ef41Sopenharmony_cifunction readPackage(requestPath) {
1401cb0ef41Sopenharmony_ci  return read(resolve(requestPath, 'package.json'));
1411cb0ef41Sopenharmony_ci}
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci/**
1441cb0ef41Sopenharmony_ci * Get the nearest parent package.json file from a given path.
1451cb0ef41Sopenharmony_ci * Return the package.json data and the path to the package.json file, or false.
1461cb0ef41Sopenharmony_ci * @param {string} checkPath The path to start searching from.
1471cb0ef41Sopenharmony_ci */
1481cb0ef41Sopenharmony_cifunction readPackageScope(checkPath) {
1491cb0ef41Sopenharmony_ci  const rootSeparatorIndex = StringPrototypeIndexOf(checkPath, sep);
1501cb0ef41Sopenharmony_ci  let separatorIndex;
1511cb0ef41Sopenharmony_ci  do {
1521cb0ef41Sopenharmony_ci    separatorIndex = StringPrototypeLastIndexOf(checkPath, sep);
1531cb0ef41Sopenharmony_ci    checkPath = StringPrototypeSlice(checkPath, 0, separatorIndex);
1541cb0ef41Sopenharmony_ci    if (StringPrototypeEndsWith(checkPath, sep + 'node_modules')) {
1551cb0ef41Sopenharmony_ci      return false;
1561cb0ef41Sopenharmony_ci    }
1571cb0ef41Sopenharmony_ci    const pjson = readPackage(checkPath + sep);
1581cb0ef41Sopenharmony_ci    if (pjson.exists) {
1591cb0ef41Sopenharmony_ci      return {
1601cb0ef41Sopenharmony_ci        data: pjson,
1611cb0ef41Sopenharmony_ci        path: checkPath,
1621cb0ef41Sopenharmony_ci      };
1631cb0ef41Sopenharmony_ci    }
1641cb0ef41Sopenharmony_ci  } while (separatorIndex > rootSeparatorIndex);
1651cb0ef41Sopenharmony_ci  return false;
1661cb0ef41Sopenharmony_ci}
1671cb0ef41Sopenharmony_ci
1681cb0ef41Sopenharmony_cimodule.exports = {
1691cb0ef41Sopenharmony_ci  read,
1701cb0ef41Sopenharmony_ci  readPackage,
1711cb0ef41Sopenharmony_ci  readPackageScope,
1721cb0ef41Sopenharmony_ci};
173