UNPKG

piral-cli

Version:

The standard CLI for creating and building a Piral instance or a Pilet.

525 lines • 20.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.determineNpmClient = determineNpmClient; exports.isMonorepoPackageRef = isMonorepoPackageRef; exports.installNpmDependencies = installNpmDependencies; exports.installNpmPackageFromOptionalRegistry = installNpmPackageFromOptionalRegistry; exports.uninstallNpmPackage = uninstallNpmPackage; exports.installNpmPackage = installNpmPackage; exports.initNpmProject = initNpmProject; exports.publishNpmPackage = publishNpmPackage; exports.createNpmPackage = createNpmPackage; exports.findNpmTarball = findNpmTarball; exports.findSpecificVersion = findSpecificVersion; exports.findLatestVersion = findLatestVersion; exports.isLocalPackage = isLocalPackage; exports.isNpmPackage = isNpmPackage; exports.makeNpmAlias = makeNpmAlias; exports.isGitPackage = isGitPackage; exports.isRemotePackage = isRemotePackage; exports.makeGitUrl = makeGitUrl; exports.makeFilePath = makeFilePath; exports.dissectPackageName = dissectPackageName; exports.getCurrentPackageDetails = getCurrentPackageDetails; exports.tryResolvePackage = tryResolvePackage; exports.findPackageRoot = findPackageRoot; exports.isLinkedPackage = isLinkedPackage; exports.combinePackageRef = combinePackageRef; exports.getPackageName = getPackageName; exports.getFilePackageVersion = getFilePackageVersion; exports.getGitPackageVersion = getGitPackageVersion; exports.getPackageVersion = getPackageVersion; exports.makePiletExternals = makePiletExternals; exports.mergeExternals = mergeExternals; exports.makeExternals = makeExternals; const path_1 = require("path"); const fs_1 = require("fs"); const log_1 = require("./log"); const config_1 = require("./config"); const constants_1 = require("./constants"); const inspect_1 = require("./inspect"); const io_1 = require("./io"); const npm_clients_1 = require("../npm-clients"); const helpers_1 = require("../helpers"); const external_1 = require("../external"); const gitPrefix = 'git+'; const filePrefix = 'file:'; const npmPrefix = 'npm:'; const pathPrefixes = ['/', './', '../', '.\\', '..\\', '~/', '~\\', filePrefix]; function isProjectReference(name) { const target = (0, path_1.resolve)(name, constants_1.packageJson); return (0, io_1.checkExists)(target); } function resolveAbsPath(basePath, fullName) { const prefixed = fullName.startsWith(filePrefix); const relPath = !prefixed ? fullName : fullName.replace(filePrefix, ''); return (0, path_1.resolve)(basePath, relPath); } async function detectMonorepoRoot(root) { let previous = root; do { if (await (0, io_1.checkExists)((0, path_1.resolve)(root, 'lerna.json'))) { return [root, 'lerna']; } if (await (0, io_1.checkExists)((0, path_1.resolve)(root, 'rush.json'))) { return [root, 'rush']; } if (await (0, io_1.checkExists)((0, path_1.resolve)(root, 'pnpm-workspace.yaml'))) { return [root, 'pnpm']; } const pj = await (0, io_1.readJson)(root, constants_1.packageJson); if (Array.isArray(pj?.workspaces)) { if (await (0, io_1.checkExists)((0, path_1.resolve)(root, '.pnp.cjs'))) { return [root, 'pnp']; } if (await (0, io_1.checkExists)((0, path_1.resolve)(root, 'yarn.lock'))) { return [root, 'yarn']; } return [root, 'npm']; } previous = root; root = (0, path_1.dirname)(root); } while (root !== previous); return []; } async function determineWrapperClient(root) { const searchedClients = await (0, npm_clients_1.detectWrapperClients)(root); const foundClients = searchedClients.filter((m) => m.result).map((m) => m.client); if (foundClients.length > 0) { const [client] = foundClients; if (foundClients.length > 1) { (0, log_1.log)('generalWarning_0001', `Found multiple clients via their lock or config files: "${foundClients.join('", "')}".`); } (0, log_1.log)('generalDebug_0003', `Found valid direct client via lock or config file: "${client}".`); return client; } const defaultClient = config_1.config.npmClient; if ((0, npm_clients_1.isWrapperClient)(defaultClient)) { (0, log_1.log)('generalDebug_0003', `Using the default client: "${defaultClient}".`); return defaultClient; } return undefined; } async function determineDirectClient(root) { const searchedClients = await (0, npm_clients_1.detectDirectClients)(root); const foundClients = searchedClients.filter((m) => m.result).map((m) => m.client); if (foundClients.length > 0) { const [client] = foundClients; if (foundClients.length > 1) { (0, log_1.log)('generalWarning_0001', `Found multiple clients via their lock or config files: "${foundClients.join('", "')}".`); } (0, log_1.log)('generalDebug_0003', `Found valid direct client via lock or config file: "${client}".`); return client; } const defaultClient = config_1.config.npmClient; if ((0, npm_clients_1.isDirectClient)(defaultClient)) { (0, log_1.log)('generalDebug_0003', `Using the default client: "${defaultClient}".`); return defaultClient; } (0, log_1.log)('generalDebug_0003', 'Using the fallback "npm" client.'); return 'npm'; } async function getMonorepo(root, client) { const [path, retrieved] = await detectMonorepoRoot(root); if (path && retrieved === client) { return path; } return undefined; } /** * For details about how this works consult issue * https://github.com/smapiot/piral/issues/203 * @param root The project's root directory. * @param selected The proposed ("selected") npm client. */ async function determineNpmClient(root, selected) { if (!selected || !helpers_1.clientTypeKeys.includes(selected)) { (0, log_1.log)('generalDebug_0003', 'No npm client selected. Checking for lock or config files ...'); const [direct, wrapper] = await Promise.all([determineDirectClient(root), determineWrapperClient(root)]); return { direct, wrapper, monorepo: await getMonorepo(root, wrapper || direct), }; } else if ((0, npm_clients_1.isDirectClient)(selected)) { return { proposed: selected, direct: selected, monorepo: await getMonorepo(root, selected), }; } else { return { proposed: selected, direct: await determineDirectClient(root), wrapper: selected, monorepo: await getMonorepo(root, selected), }; } } async function isMonorepoPackageRef(refName, client) { if (client.monorepo) { const clientName = client.wrapper || client.direct; const clientApi = npm_clients_1.clients[clientName]; return await clientApi.isProject(client.monorepo, refName); } return false; } function installNpmDependencies(client, target = '.') { const { installDependencies } = npm_clients_1.clients[client.direct]; return installDependencies(target); } async function installNpmPackageFromOptionalRegistry(packageRef, target, registry) { const client = await determineNpmClient(target, 'npm'); try { await installNpmPackage(client, packageRef, target, '--registry', registry); } catch (e) { if (registry === constants_1.defaultRegistry) { throw e; } await installNpmPackage(client, packageRef, target, '--registry', constants_1.defaultRegistry); } } async function uninstallNpmPackage(client, packageRef, target = '.', ...flags) { const name = client.direct; try { const { uninstallPackage } = npm_clients_1.clients[name]; return await uninstallPackage(packageRef, target, ...flags); } catch (ex) { (0, log_1.log)('generalError_0002', `Could not uninstall the package "${packageRef}" using ${name}. Make sure ${name} is correctly installed and accessible: ${ex}`); throw ex; } } async function installNpmPackage(client, packageRef, target = '.', ...flags) { const name = client.direct; try { const { installPackage } = npm_clients_1.clients[name]; return await installPackage(packageRef, target, ...flags); } catch (ex) { (0, log_1.log)('generalError_0002', `Could not install the package "${packageRef}" using ${name}. Make sure ${name} is correctly installed and accessible: ${ex}`); throw ex; } } function initNpmProject(client, projectName, target) { const { initProject } = npm_clients_1.clients[client.wrapper || client.direct]; return initProject(projectName, target); } function publishNpmPackage(target = '.', file = '*.tgz', flags = [], interactive = false) { const { publishPackage, loginUser } = npm_clients_1.clients.npm; return publishPackage(target, file, ...flags).catch((err) => { if (!interactive) { throw err; } return loginUser().then(() => publishNpmPackage(target, file, flags, false)); }); } function createNpmPackage(target = '.') { const { createPackage } = npm_clients_1.clients.npm; return createPackage(target); } function findNpmTarball(packageRef) { const { findTarball } = npm_clients_1.clients.npm; return findTarball(packageRef); } function findSpecificVersion(packageName, version) { const { findSpecificVersion } = npm_clients_1.clients.npm; return findSpecificVersion(packageName, version); } function findLatestVersion(packageName) { const { findSpecificVersion } = npm_clients_1.clients.npm; return findSpecificVersion(packageName, 'latest'); } function isLocalPackage(baseDir, fullName) { (0, log_1.log)('generalDebug_0003', 'Checking if its a local package ...'); if (fullName) { if (pathPrefixes.some((prefix) => fullName.startsWith(prefix))) { (0, log_1.log)('generalDebug_0003', 'Found a local package by name.'); return true; } else if (fullName.endsWith('.tgz')) { (0, log_1.log)('generalDebug_0003', ' Verifying if local path exists ...'); if ((0, fs_1.existsSync)((0, path_1.resolve)(baseDir, fullName))) { (0, log_1.log)('generalDebug_0003', 'Found a potential local package by path.'); return true; } } return fullName.startsWith(filePrefix); } return false; } function isNpmPackage(fullName) { (0, log_1.log)('generalDebug_0003', 'Checking if its an npm alias ...'); if (fullName) { const npmed = fullName.startsWith(npmPrefix); if (npmed && fullName.substring(npmPrefix.length + 1).indexOf('@') !== -1) { (0, log_1.log)('generalDebug_0003', 'Found an npm package alias by name.'); return true; } } return false; } function makeNpmAlias(name, version) { return `${npmPrefix}${name}@${version}`; } function isGitPackage(fullName) { (0, log_1.log)('generalDebug_0003', 'Checking if its a git package ...'); if (fullName) { const gitted = fullName.startsWith(gitPrefix); if (gitted || /^(https?|ssh):\/\/.*\.git$/.test(fullName)) { (0, log_1.log)('generalDebug_0003', 'Found a git package by name.'); return true; } } return false; } function isRemotePackage(fullName) { (0, log_1.log)('generalDebug_0003', 'Checking if its a remote package ...'); if (fullName && /^https?:\/\/.*/.test(fullName)) { (0, log_1.log)('generalDebug_0003', 'Found a remote package by name.'); return true; } return false; } function makeGitUrl(fullName) { const gitted = fullName.startsWith(gitPrefix); return gitted ? fullName : `${gitPrefix}${fullName}`; } function makeFilePath(basePath, fullName) { const absPath = resolveAbsPath(basePath, fullName); return `${filePrefix}${absPath}`; } /** * Looks at the provided package name and normalizes it * resulting in the following tuple: * [ * normalized / real package name, * found package version / version identifier, * indicator if an explicit version was used, * the used package type * ] * @param baseDir The base directory of the current operation. * @param fullName The provided package name. * @param client The used npm client. */ async function dissectPackageName(baseDir, fullName, client) { if (isGitPackage(fullName)) { const gitUrl = makeGitUrl(fullName); return [gitUrl, 'latest', false, 'git']; } else if (isRemotePackage(fullName)) { return [fullName, 'latest', false, 'remote']; } else if (isLocalPackage(baseDir, fullName)) { const fullPath = resolveAbsPath(baseDir, fullName); const exists = await (0, io_1.checkExists)(fullPath); if (!exists) { (0, log_1.fail)('scaffoldPathDoesNotExist_0030', fullPath); } const isReference = await isProjectReference(fullPath); if (isReference) { (0, log_1.fail)('projectReferenceNotSupported_0032', fullPath); } return [fullPath, 'latest', false, 'file']; } else if (await isMonorepoPackageRef(fullName, client)) { return [fullName, '*', false, 'monorepo']; } else { const index = fullName.indexOf('@', 1); const type = 'registry'; if (index !== -1) { return [fullName.substring(0, index), fullName.substring(index + 1), true, type]; } return [fullName, 'latest', false, type]; } } /** * Looks at the current package name / version and * normalizes it resulting in the following tuple: * [ * normalized / real package name, * found package version / version identifier, * ] * @param baseDir The base directory of the current operation. * @param sourceName The used package name. * @param sourceVersion The used package version. * @param desired The desired package version. */ async function getCurrentPackageDetails(baseDir, sourceName, sourceVersion, desired, root) { (0, log_1.log)('generalDebug_0003', `Checking package details in "${baseDir}" ...`); if (isLocalPackage(baseDir, desired)) { const fullPath = (0, path_1.resolve)(baseDir, desired); const exists = await (0, io_1.checkExists)(fullPath); if (!exists) { (0, log_1.fail)('upgradePathDoesNotExist_0031', fullPath); } const isReference = await isProjectReference(fullPath); if (isReference) { (0, log_1.fail)('projectReferenceNotSupported_0032', fullPath); } return [fullPath, getFilePackageVersion(fullPath, root)]; } else if (isGitPackage(desired)) { const gitUrl = makeGitUrl(desired); return [gitUrl, getGitPackageVersion(gitUrl)]; } else if (sourceVersion && sourceVersion.startsWith('file:')) { (0, log_1.log)('localeFileForUpgradeMissing_0050'); } else if (sourceVersion && sourceVersion.startsWith('git+')) { if (desired === 'latest') { const gitUrl = desired; return [gitUrl, getGitPackageVersion(gitUrl)]; } else { (0, log_1.log)('gitLatestForUpgradeMissing_0051'); } } return [combinePackageRef(sourceName, desired, 'registry'), desired]; } function tryResolve(packageName, baseDir = process.cwd()) { try { return (0, external_1.getModulePath)(baseDir, packageName); } catch { return undefined; } } function tryResolvePackage(name, baseDir = undefined) { const path = baseDir ? tryResolve(name, baseDir) : tryResolve(name); const root = baseDir || process.cwd(); if (!path) { (0, log_1.log)('generalDebug_0003', `Could not resolve the package "${name}" in "${root}".`); } else { (0, log_1.log)('generalVerbose_0004', `Resolved the package "${name}" (from "${root}") to be "${path}".`); } return path; } function findPackageRoot(pck, baseDir) { return tryResolvePackage(`${pck}/${constants_1.packageJson}`, baseDir); } function isLinkedPackage(name, type, hadVersion, target) { if (type === 'monorepo') { return true; } else if (type === 'registry' && !hadVersion) { const root = findPackageRoot(name, target); return typeof root === 'string'; } return false; } function combinePackageRef(name, version, type) { if (type === 'registry') { const tag = version || 'latest'; return `${name}@${tag}`; } return name; } async function getPackageName(root, name, type) { switch (type) { case 'file': const originalPackageJson = await (0, io_1.readJson)(name, constants_1.packageJson); if (!originalPackageJson.name) { const p = (0, path_1.resolve)(process.cwd(), name); try { const s = (0, fs_1.createReadStream)(p); const i = await (0, inspect_1.inspectPackage)(s); return i.name; } catch (err) { (0, log_1.log)('generalError_0002', `Could not open package tarball at "${p}": "${err}`); return undefined; } } return originalPackageJson.name; case 'git': const pj = await (0, io_1.readJson)(root, constants_1.packageJson); const dd = pj.devDependencies || {}; return Object.keys(dd).filter((dep) => dd[dep] === name)[0]; case 'monorepo': case 'registry': return name; case 'remote': throw new Error('Cannot get the package name for a remote package!'); } } function getFilePackageVersion(sourceName, root) { const path = (0, path_1.relative)(root, sourceName); return `${filePrefix}${path}`; } function getGitPackageVersion(sourceName) { return `${sourceName}`; } function getPackageVersion(hadVersion, sourceName, sourceVersion, type, root) { switch (type) { case 'monorepo': return sourceVersion; case 'registry': return hadVersion && sourceVersion; case 'file': return getFilePackageVersion(sourceName, root); case 'git': return getGitPackageVersion(sourceName); } } async function getExternalsFrom(root, packageName) { try { const target = (0, external_1.getModulePath)(root, `${packageName}/${constants_1.packageJson}`); const dir = (0, path_1.dirname)(target); const { sharedDependencies } = await (0, io_1.readJson)(dir, constants_1.packageJson); return sharedDependencies; } catch (err) { (0, log_1.log)('generalError_0002', `Could not get externals from "${packageName}": "${err}`); return undefined; } } async function getCoreExternals(root, dependencies) { for (const frameworkLib of constants_1.frameworkLibs) { if (dependencies[frameworkLib]) { const deps = await getExternalsFrom(root, frameworkLib); if (deps) { return deps; } } } (0, log_1.log)('frameworkLibMissing_0078', constants_1.frameworkLibs); return []; } async function makePiletExternals(root, dependencies, fromEmulator, piralInfo) { if (fromEmulator) { const { sharedDependencies = constants_1.legacyCoreExternals } = piralInfo; return sharedDependencies; } else { return await getCoreExternals(root, dependencies); } } function mergeExternals(customExternals, coreExternals = []) { if (customExternals && Array.isArray(customExternals)) { const [include, exclude] = customExternals.reduce((prev, curr) => { if (typeof curr === 'string') { if (curr.startsWith('!')) { prev[1].push(curr.substring(1)); } else { prev[0].push(curr); } } return prev; }, [[], []]); const all = exclude.includes('*') ? include : [...include, ...coreExternals]; return all.filter((m, i, arr) => !exclude.includes(m) && arr.indexOf(m) === i); } return coreExternals; } async function makeExternals(root, dependencies, externals) { const coreExternals = await getCoreExternals(root, dependencies); return mergeExternals(externals, coreExternals); } //# sourceMappingURL=npm.js.map