UNPKG

@backstage/cli

Version:

CLI for developing Backstage plugins and apps

227 lines (221 loc) • 7.74 kB
'use strict'; var fs = require('fs-extra'); var semver = require('semver'); var parsers = require('@yarnpkg/parsers'); var lockfile = require('@yarnpkg/lockfile'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs); var semver__default = /*#__PURE__*/_interopDefaultLegacy(semver); const ENTRY_PATTERN = /^((?:@[^/]+\/)?[^@/]+)@(.+)$/; const NEW_HEADER = `${[ `# This file is generated by running "yarn install" inside your project. `, `# Manual changes might be lost - proceed with caution! ` ].join(``)} `; const LEGACY_REGEX = /^(#.*(\r?\n))*?#\s+yarn\s+lockfile\s+v1\r?\n/i; const SPECIAL_OBJECT_KEYS = [ `__metadata`, `version`, `resolution`, `dependencies`, `peerDependencies`, `dependenciesMeta`, `peerDependenciesMeta`, `binaries` ]; class Lockfile { constructor(packages, data, legacy = false) { this.packages = packages; this.data = data; this.legacy = legacy; } static async load(path) { const lockfileContents = await fs__default["default"].readFile(path, "utf8"); return Lockfile.parse(lockfileContents); } static parse(content) { var _a; const legacy = LEGACY_REGEX.test(content); let data; try { data = parsers.parseSyml(content); } catch (err) { throw new Error(`Failed yarn.lock parse, ${err}`); } const packages = /* @__PURE__ */ new Map(); for (const [key, value] of Object.entries(data)) { if (SPECIAL_OBJECT_KEYS.includes(key)) continue; const [, name, ranges] = (_a = ENTRY_PATTERN.exec(key)) != null ? _a : []; if (!name) { throw new Error(`Failed to parse yarn.lock entry '${key}'`); } let queries = packages.get(name); if (!queries) { queries = []; packages.set(name, queries); } for (let range of ranges.split(/\s*,\s*/)) { if (range.startsWith(`${name}@`)) { range = range.slice(`${name}@`.length); } if (range.startsWith("npm:")) { range = range.slice("npm:".length); } queries.push({ range, version: value.version, dataKey: key }); } } return new Lockfile(packages, data, legacy); } /** Get the entries for a single package in the lockfile */ get(name) { return this.packages.get(name); } /** Returns the name of all packages available in the lockfile */ keys() { return this.packages.keys(); } /** Analyzes the lockfile to identify possible actions and warnings for the entries */ analyze(options) { var _a; const { filter, localPackages } = options; const result = { invalidRanges: [], newVersions: [], newRanges: [] }; for (const [name, allEntries] of this.packages) { if (filter && !filter(name)) { continue; } const invalid = allEntries.filter( (e) => !semver__default["default"].validRange(e.range) && !e.range.startsWith("workspace:") ); result.invalidRanges.push( ...invalid.map(({ range }) => ({ name, range })) ); const entries = allEntries.filter((e) => semver__default["default"].validRange(e.range)); if (entries.length < 2) { continue; } const versions = Array.from(new Set(entries.map((e) => e.version))).map((v) => { if (v === "0.0.0-use.local") { const local = localPackages.get(name); if (!local) { throw new Error(`No local package found for ${name}`); } if (!local.packageJson.version) { throw new Error(`No version found for local package ${name}`); } return { entryVersion: v, actualVersion: local.packageJson.version }; } return { entryVersion: v, actualVersion: v }; }).sort((v1, v2) => semver__default["default"].rcompare(v1.actualVersion, v2.actualVersion)); if (versions.length < 2) { continue; } const acceptedVersions = /* @__PURE__ */ new Set(); for (const { version, range } of entries) { const acceptedVersion = versions.find( (v) => semver__default["default"].satisfies(v.actualVersion, range) ); if (!acceptedVersion) { throw new Error( `No existing version was accepted for range ${range}, searching through ${versions}, for package ${name}` ); } if (acceptedVersion.entryVersion !== version) { result.newVersions.push({ name, range, newVersion: acceptedVersion.entryVersion, oldVersion: version }); } acceptedVersions.add(acceptedVersion.actualVersion); } if (acceptedVersions.size === 1) { continue; } const maxVersion = Array.from(acceptedVersions).sort(semver__default["default"].rcompare)[0]; const maxEntry = (_a = entries.filter((e) => semver__default["default"].satisfies(maxVersion, e.range)).map((e) => ({ e, min: semver__default["default"].minVersion(e.range) })).filter((p) => p.min).sort((a, b) => semver__default["default"].rcompare(a.min, b.min))[0]) == null ? void 0 : _a.e; if (!maxEntry) { throw new Error( `No entry found that satisfies max version '${maxVersion}'` ); } for (const { version, range } of entries) { if (semver__default["default"].satisfies(maxVersion, range)) { continue; } result.newRanges.push({ name, oldRange: range, newRange: maxEntry.range, oldVersion: version, newVersion: maxVersion }); } } return result; } remove(name, range) { var _a; const query = `${name}@${range}`; const existed = Boolean(this.data[query]); delete this.data[query]; const newEntries = (_a = this.packages.get(name)) == null ? void 0 : _a.filter((e) => e.range !== range); if (newEntries) { this.packages.set(name, newEntries); } return existed; } /** Modifies the lockfile by bumping packages to the suggested versions */ replaceVersions(results) { var _a; for (const { name, range, oldVersion, newVersion } of results) { const query = `${name}@${range}`; const entryData = this.data[query]; if (!entryData) { throw new Error(`No entry data for ${query}`); } if (entryData.version !== oldVersion) { throw new Error( `Expected existing version data for ${query} to be ${oldVersion}, was ${entryData.version}` ); } const matchingEntry = Object.entries(this.data).find( ([q, e]) => q.startsWith(`${name}@`) && e.version === newVersion ); if (!matchingEntry) { throw new Error( `No matching entry found for ${name} at version ${newVersion}` ); } this.data[query] = matchingEntry[1]; const entry = (_a = this.packages.get(name)) == null ? void 0 : _a.find((e) => e.range === range); if (!entry) { throw new Error(`No entry data for ${query}`); } if (entry.version !== oldVersion) { throw new Error( `Expected existing version data for ${query} to be ${oldVersion}, was ${entryData.version}` ); } entry.version = newVersion; } } async save(path) { await fs__default["default"].writeFile(path, this.toString(), "utf8"); } toString() { return this.legacy ? lockfile.stringify(this.data) : NEW_HEADER + parsers.stringifySyml(this.data); } } exports.Lockfile = Lockfile; //# sourceMappingURL=Lockfile-eced6070.cjs.js.map