UNPKG

@pnpm/read-project-manifest

Version:

Read a project manifest (called package.json in most cases)

221 lines 8.11 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.safeReadProjectManifestOnly = safeReadProjectManifestOnly; exports.readProjectManifest = readProjectManifest; exports.readProjectManifestOnly = readProjectManifestOnly; exports.tryReadProjectManifest = tryReadProjectManifest; exports.readExactProjectManifest = readExactProjectManifest; const fs_1 = require("fs"); const path_1 = __importDefault(require("path")); const error_1 = require("@pnpm/error"); const text_comments_parser_1 = require("@pnpm/text.comments-parser"); const write_project_manifest_1 = require("@pnpm/write-project-manifest"); const read_yaml_file_1 = __importDefault(require("read-yaml-file")); const detect_indent_1 = __importDefault(require("@gwhitney/detect-indent")); const fast_deep_equal_1 = __importDefault(require("fast-deep-equal")); const is_windows_1 = __importDefault(require("is-windows")); const readFile_1 = require("./readFile"); async function safeReadProjectManifestOnly(projectDir) { try { return await readProjectManifestOnly(projectDir); } catch (err) { // eslint-disable-line if (err.code === 'ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND') { return null; } throw err; } } async function readProjectManifest(projectDir) { const result = await tryReadProjectManifest(projectDir); if (result.manifest !== null) { return result; } throw new error_1.PnpmError('NO_IMPORTER_MANIFEST_FOUND', `No package.json (or package.yaml, or package.json5) was found in "${projectDir}".`); } async function readProjectManifestOnly(projectDir) { const { manifest } = await readProjectManifest(projectDir); return manifest; } async function tryReadProjectManifest(projectDir) { try { const manifestPath = path_1.default.join(projectDir, 'package.json'); const { data, text } = await (0, readFile_1.readJsonFile)(manifestPath); return { fileName: 'package.json', manifest: data, writeProjectManifest: createManifestWriter({ ...detectFileFormatting(text), initialManifest: data, manifestPath, }), }; } catch (err) { // eslint-disable-line if (err.code !== 'ENOENT') throw err; } try { const manifestPath = path_1.default.join(projectDir, 'package.json5'); const { data, text } = await (0, readFile_1.readJson5File)(manifestPath); return { fileName: 'package.json5', manifest: data, writeProjectManifest: createManifestWriter({ ...detectFileFormattingAndComments(text), initialManifest: data, manifestPath, }), }; } catch (err) { // eslint-disable-line if (err.code !== 'ENOENT') throw err; } try { const manifestPath = path_1.default.join(projectDir, 'package.yaml'); const manifest = await readPackageYaml(manifestPath); return { fileName: 'package.yaml', manifest, writeProjectManifest: createManifestWriter({ initialManifest: manifest, manifestPath }), }; } catch (err) { // eslint-disable-line if (err.code !== 'ENOENT') throw err; } if ((0, is_windows_1.default)()) { // ENOTDIR isn't used on Windows, but pnpm expects it. let s; try { s = await fs_1.promises.stat(projectDir); } catch (err) { // eslint-disable-line // Ignore } if ((s != null) && !s.isDirectory()) { const err = new Error(`"${projectDir}" is not a directory`); // @ts-expect-error err['code'] = 'ENOTDIR'; throw err; } } const filePath = path_1.default.join(projectDir, 'package.json'); return { fileName: 'package.json', manifest: null, writeProjectManifest: async (manifest) => (0, write_project_manifest_1.writeProjectManifest)(filePath, manifest), }; } function detectFileFormattingAndComments(text) { const { comments, text: newText, hasFinalNewline } = (0, text_comments_parser_1.extractComments)(text); return { comments, indent: (0, detect_indent_1.default)(newText).indent, insertFinalNewline: hasFinalNewline, }; } function detectFileFormatting(text) { return { indent: (0, detect_indent_1.default)(text).indent, insertFinalNewline: text.endsWith('\n'), }; } async function readExactProjectManifest(manifestPath) { const base = path_1.default.basename(manifestPath).toLowerCase(); switch (base) { case 'package.json': { const { data, text } = await (0, readFile_1.readJsonFile)(manifestPath); return { manifest: data, writeProjectManifest: createManifestWriter({ ...detectFileFormatting(text), initialManifest: data, manifestPath, }), }; } case 'package.json5': { const { data, text } = await (0, readFile_1.readJson5File)(manifestPath); return { manifest: data, writeProjectManifest: createManifestWriter({ ...detectFileFormattingAndComments(text), initialManifest: data, manifestPath, }), }; } case 'package.yaml': { const manifest = await readPackageYaml(manifestPath); return { manifest, writeProjectManifest: createManifestWriter({ initialManifest: manifest, manifestPath }), }; } } throw new Error(`Not supported manifest name "${base}"`); } async function readPackageYaml(filePath) { try { return await (0, read_yaml_file_1.default)(filePath); } catch (err) { // eslint-disable-line if (err.name !== 'YAMLException') throw err; err.message = `${err.message}\nin ${filePath}`; err.code = 'ERR_PNPM_YAML_PARSE'; throw err; } } function createManifestWriter(opts) { let initialManifest = normalize(opts.initialManifest); return async (updatedManifest, force) => { updatedManifest = normalize(updatedManifest); if (force === true || !(0, fast_deep_equal_1.default)(initialManifest, updatedManifest)) { await (0, write_project_manifest_1.writeProjectManifest)(opts.manifestPath, updatedManifest, { comments: opts.comments, indent: opts.indent, insertFinalNewline: opts.insertFinalNewline, }); initialManifest = normalize(updatedManifest); return Promise.resolve(undefined); } return Promise.resolve(undefined); }; } const dependencyKeys = new Set([ 'dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies', ]); function normalize(manifest) { const result = {}; for (const key in manifest) { if (Object.prototype.hasOwnProperty.call(manifest, key)) { const value = manifest[key]; if (typeof value !== 'object' || !dependencyKeys.has(key)) { result[key] = structuredClone(value); } else { const keys = Object.keys(value); if (keys.length !== 0) { keys.sort(); const sortedValue = {}; for (const k of keys) { // @ts-expect-error this is fine sortedValue[k] = value[k]; } result[key] = sortedValue; } } } } return result; } //# sourceMappingURL=index.js.map