UNPKG

@nx/js

Version:

The JS plugin for Nx contains executors and generators that provide the best experience for developing JavaScript and TypeScript projects.

154 lines (153 loc) • 6.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = pruneLockfileExecutor; exports.resolveCatalogReferences = resolveCatalogReferences; const devkit_1 = require("@nx/devkit"); const internal_1 = require("@nx/devkit/internal"); const fs_1 = require("fs"); const path_1 = require("path"); const utils_1 = require("nx/src/tasks-runner/utils"); // eslint-disable-next-line @typescript-eslint/no-restricted-imports const lock_file_1 = require("nx/src/plugins/js/lock-file/lock-file"); // eslint-disable-next-line @typescript-eslint/no-restricted-imports const get_workspace_packages_from_graph_1 = require("nx/src/plugins/js/utils/get-workspace-packages-from-graph"); const strip_glob_to_base_dir_1 = require("../../utils/strip-glob-to-base-dir"); async function pruneLockfileExecutor(schema, context) { devkit_1.logger.log('Pruning lockfile...'); const outputDirectory = getOutputDir(schema, context); const packageJson = resolveCatalogReferences(getPackageJson(schema, context)); mergeAllowScripts(packageJson); const packageManager = (0, devkit_1.detectPackageManager)(devkit_1.workspaceRoot); if (packageManager === 'bun') { devkit_1.logger.warn('Bun lockfile generation is not supported. Only package.json will be generated. Run "bun install" in the output directory if needed.'); (0, fs_1.writeFileSync)((0, path_1.join)(outputDirectory, 'package.json'), JSON.stringify(packageJson, null, 2)); } else { const { lockfileName, lockFile } = createPrunedLockfile(packageJson, context.projectGraph); const lockfileOutputPath = (0, path_1.join)(outputDirectory, lockfileName); (0, fs_1.writeFileSync)(lockfileOutputPath, lockFile); (0, fs_1.writeFileSync)((0, path_1.join)(outputDirectory, 'package.json'), JSON.stringify(packageJson, null, 2)); devkit_1.logger.log(`Lockfile pruned: ${lockfileOutputPath}`); } return { success: true, }; } function createPrunedLockfile(packageJson, graph) { const packageManager = (0, devkit_1.detectPackageManager)(devkit_1.workspaceRoot); const lockfileName = (0, lock_file_1.getLockFileName)(packageManager); const lockFile = (0, lock_file_1.createLockFile)(packageJson, graph, packageManager); const workspacePackages = (0, get_workspace_packages_from_graph_1.getWorkspacePackagesFromGraph)(graph); for (const [pkgName, pkgVersion] of Object.entries(packageJson.dependencies ?? {})) { if (pkgVersion.startsWith('workspace:') || pkgVersion.startsWith('file:') || pkgVersion.startsWith('link:') || workspacePackages.has(pkgName)) { packageJson.dependencies[pkgName] = `file:./workspace_modules/${pkgName}`; } } return { lockfileName, lockFile, }; } /** * npm reads the `allowScripts` install-script allowlist only from the install * root, but `npm approve-scripts` writes it to the workspace root, so it never * lives in the project package.json the prune output is built from. Carry the * root allowlist over, with project-level entries preserved and winning on * conflict. Mirrors the `pnpm.allowBuilds` handling in createPackageJson. */ function mergeAllowScripts(packageJson) { const rootPackageJson = (0, devkit_1.readJsonFile)((0, path_1.join)(devkit_1.workspaceRoot, 'package.json')); if (!rootPackageJson.allowScripts) { return; } packageJson.allowScripts = { ...rootPackageJson.allowScripts, ...packageJson.allowScripts, }; } function resolveCatalogReferences(packageJson) { const manager = (0, internal_1.getCatalogManager)(devkit_1.workspaceRoot); if (!manager) { return packageJson; } const sections = [ 'dependencies', 'optionalDependencies', 'devDependencies', 'peerDependencies', ]; const resolved = { ...packageJson }; for (const section of sections) { const deps = packageJson[section]; if (!deps) { continue; } const resolvedDeps = { ...deps }; for (const [packageName, version] of Object.entries(deps)) { if (!manager.isCatalogReference(version)) { continue; } const resolvedVersion = manager.resolveCatalogReference(devkit_1.workspaceRoot, packageName, version); if (!resolvedVersion) { throw new Error(`Could not resolve catalog reference for package ${packageName}@${version}.`); } resolvedDeps[packageName] = resolvedVersion; } resolved[section] = resolvedDeps; } return resolved; } function getPackageJson(schema, context) { const target = (0, devkit_1.parseTargetString)(schema.buildTarget, context); const project = context.projectGraph.nodes[target.project].data; const packageJsonPath = (0, path_1.join)(devkit_1.workspaceRoot, project.root, 'package.json'); if (!(0, fs_1.existsSync)(packageJsonPath)) { throw new Error(`${packageJsonPath} does not exist.`); } const packageJson = (0, devkit_1.readJsonFile)(packageJsonPath); return packageJson; } function getOutputDir(schema, context) { let outputDir = schema.outputPath; if (outputDir) { outputDir = normalizeOutputPath(outputDir); if ((0, fs_1.existsSync)(outputDir)) { return outputDir; } } const target = (0, devkit_1.parseTargetString)(schema.buildTarget, context); const project = context.projectGraph.nodes[target.project].data; const buildTarget = project.targets[target.target]; let maybeOutputPath = buildTarget.outputs?.[0] ?? buildTarget.options.outputPath ?? buildTarget.options.outputDir; if (!maybeOutputPath) { throw new Error(`Could not infer an output directory from the '${schema.buildTarget}' target. Please provide 'outputPath'.`); } maybeOutputPath = (0, utils_1.interpolate)(maybeOutputPath, { workspaceRoot: devkit_1.workspaceRoot, projectRoot: project.root, projectName: project.name, options: { ...(buildTarget.options ?? {}), }, }); outputDir = normalizeOutputPath(maybeOutputPath); if (!(0, fs_1.existsSync)(outputDir)) { throw new Error(`The output directory '${outputDir}' inferred from the '${schema.buildTarget}' target does not exist.\nPlease ensure a build has run first, and that the path is correct. Otherwise, please provide 'outputPath'.`); } return outputDir; } function normalizeOutputPath(outputPath) { outputPath = (0, strip_glob_to_base_dir_1.stripGlobToBaseDir)(outputPath); if (!outputPath.startsWith(devkit_1.workspaceRoot)) { outputPath = (0, path_1.join)(devkit_1.workspaceRoot, outputPath); } if (!(0, fs_1.lstatSync)(outputPath).isDirectory()) { outputPath = (0, path_1.dirname)(outputPath); } return outputPath; }