UNPKG

snyk-nodejs-lockfile-parser

Version:
130 lines 5.51 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getLockfileVersionFromFile = exports.NodeLockfileVersion = void 0; exports.getPnpmLockfileVersion = getPnpmLockfileVersion; exports.getYarnLockfileVersion = getYarnLockfileVersion; exports.getNpmLockfileVersion = getNpmLockfileVersion; exports.parseJsonFile = parseJsonFile; exports.describeLikelyJsonCause = describeLikelyJsonCause; const fs_1 = require("fs"); const js_yaml_1 = require("js-yaml"); const errors_1 = require("./errors"); const error_catalog_nodejs_public_1 = require("@snyk/error-catalog-nodejs-public"); var NodeLockfileVersion; (function (NodeLockfileVersion) { NodeLockfileVersion["NpmLockV1"] = "NPM_LOCK_V1"; NodeLockfileVersion["NpmLockV2"] = "NPM_LOCK_V2"; NodeLockfileVersion["NpmLockV3"] = "NPM_LOCK_V3"; NodeLockfileVersion["YarnLockV1"] = "YARN_LOCK_V1"; NodeLockfileVersion["YarnLockV2"] = "YARN_LOCK_V2"; NodeLockfileVersion["PnpmLockV5"] = "PNPM_LOCK_V5"; NodeLockfileVersion["PnpmLockV6"] = "PNPM_LOCK_V6"; NodeLockfileVersion["PnpmLockV9"] = "PNPM_LOCK_V9"; })(NodeLockfileVersion || (exports.NodeLockfileVersion = NodeLockfileVersion = {})); const getLockfileVersionFromFile = (targetFile) => { const lockFileContents = (0, fs_1.readFileSync)(targetFile, 'utf-8'); if (targetFile.endsWith('package-lock.json')) { return getNpmLockfileVersion(lockFileContents); } else if (targetFile.endsWith('yarn.lock')) { return getYarnLockfileVersion(lockFileContents); } else if (targetFile.endsWith('pnpm-lock.yaml')) { return getPnpmLockfileVersion(lockFileContents); } else { throw new errors_1.InvalidUserInputError(`Unknown lockfile ${targetFile}. ` + 'Please provide either package-lock.json, yarn.lock or pnpm-lock.yaml'); } }; exports.getLockfileVersionFromFile = getLockfileVersionFromFile; function getPnpmLockfileVersion(lockFileContents) { const rawPnpmLock = (0, js_yaml_1.load)(lockFileContents, { json: true, schema: js_yaml_1.FAILSAFE_SCHEMA, }); const { lockfileVersion } = rawPnpmLock; if (lockfileVersion.startsWith('5')) { return NodeLockfileVersion.PnpmLockV5; } else if (lockfileVersion.startsWith('6')) { return NodeLockfileVersion.PnpmLockV6; } else if (lockfileVersion.startsWith('9')) { return NodeLockfileVersion.PnpmLockV9; } else { throw new error_catalog_nodejs_public_1.OpenSourceEcosystems.PnpmUnsupportedLockfileVersionError(`The pnpm-lock.yaml lockfile version ${lockfileVersion} is not supported`); } } function getYarnLockfileVersion(lockFileContents) { if (lockFileContents.includes('__metadata')) { return NodeLockfileVersion.YarnLockV2; } else { return NodeLockfileVersion.YarnLockV1; } } function getNpmLockfileVersion(lockFileContents) { // Parse first; surfacing the real JSON error happens inside parseJsonFile. const lockfileJson = parseJsonFile(lockFileContents, 'package-lock.json'); // The version check runs *outside* the parse try/catch so that an // unsupported (but otherwise valid JSON) lockfile is not mis-reported as a // JSON syntax error. const lockfileVersion = lockfileJson.lockfileVersion || null; switch (lockfileVersion) { case null: case 1: return NodeLockfileVersion.NpmLockV1; case 2: return NodeLockfileVersion.NpmLockV2; case 3: return NodeLockfileVersion.NpmLockV3; default: throw new errors_1.InvalidUserInputError(`Unsupported npm lockfile version "${lockfileVersion}" in package-lock.json. ` + 'Please provide a package-lock.json with lockfileVersion 1, 2 or 3'); } } /** * Parse JSON from a manifest or lockfile. On failure throws an * InvalidUserInputError that preserves the underlying parser message * (including the position of the syntax error) and appends a best-effort hint * about the likely cause. * * `fileLabel` is the file kind shown in the error, e.g. 'package.json' or * 'package-lock.json'. */ function parseJsonFile(content, fileLabel) { try { return JSON.parse(content); } catch (e) { throw new errors_1.InvalidUserInputError(`${fileLabel} parsing failed with error ${e.message}` + describeLikelyJsonCause(content)); } } /** * Best-effort, allocation-light hint describing the most likely reason a JSON * parse failed. Inspects only the leading characters of the content, never * throws, and returns '' when nothing recognisable is found - so it is always * safe to append to a parse-error message. */ function describeLikelyJsonCause(content) { if (!content) { return ' The file is empty.'; } // A byte-order mark (UTF-8/UTF-16/UTF-32) decoded into the string. if (content.charCodeAt(0) === 0xfeff) { return ' The file begins with a byte-order mark (BOM); re-save it as UTF-8 without a BOM.'; } // NUL bytes strongly suggest the file is UTF-16/UTF-32 encoded. if (content.includes('\x00')) { return ' The file contains NUL bytes; it may be UTF-16/UTF-32 encoded. Re-save it as UTF-8.'; } // Unresolved git merge-conflict markers. if (/^(<{7}|={7}|>{7})( |$)/m.test(content)) { return ' The file appears to contain unresolved git merge-conflict markers.'; } return ''; } //# sourceMappingURL=utils.js.map