UNPKG

isolate-package

Version:

Isolate monorepo packages to form a self-contained deployable unit

1 lines 106 kB
{"version":3,"file":"isolate-B0zQOSqE.mjs","names":["fs","fs","readWantedLockfile_v9","readWantedLockfile_v8","getLockfileImporterId_v9","getLockfileImporterId_v8","pruneLockfile_v9","pruneLockfile_v8","writeWantedLockfile_v9","writeWantedLockfile_v8","path","readWantedLockfile_v9","readWantedLockfile_v8"],"sources":["../src/lib/logger.ts","../src/lib/utils/filter-object-undefined.ts","../src/lib/utils/get-package-name.ts","../src/lib/utils/filter-patched-dependencies.ts","../src/lib/utils/get-dirname.ts","../src/lib/utils/get-error-message.ts","../src/lib/utils/inspect-value.ts","../src/lib/utils/is-rush-workspace.ts","../src/lib/utils/json.ts","../src/lib/utils/log-paths.ts","../src/lib/utils/get-major-version.ts","../src/lib/package-manager/names.ts","../src/lib/package-manager/helpers/infer-from-files.ts","../src/lib/package-manager/helpers/infer-from-manifest.ts","../src/lib/package-manager/index.ts","../src/lib/utils/pack.ts","../src/lib/utils/unpack.ts","../src/lib/utils/yaml.ts","../src/lib/config.ts","../src/lib/lockfile/helpers/load-npm-config.ts","../src/lib/lockfile/helpers/generate-npm-lockfile.ts","../src/lib/lockfile/helpers/pnpm-map-importer.ts","../src/lib/lockfile/helpers/generate-pnpm-lockfile.ts","../src/lib/lockfile/helpers/generate-yarn-lockfile.ts","../src/lib/lockfile/process-lockfile.ts","../src/lib/manifest/io.ts","../src/lib/manifest/helpers/patch-internal-entries.ts","../src/lib/manifest/helpers/adapt-manifest-internal-deps.ts","../src/lib/manifest/helpers/resolve-catalog-dependencies.ts","../src/lib/manifest/helpers/adapt-internal-package-manifests.ts","../src/lib/manifest/helpers/adopt-pnpm-fields-from-root.ts","../src/lib/manifest/adapt-target-package-manifest.ts","../src/lib/manifest/validate-manifest.ts","../src/lib/output/get-build-output-dir.ts","../src/lib/output/pack-dependencies.ts","../src/lib/output/process-build-output-files.ts","../src/lib/output/unpack-dependencies.ts","../src/lib/patches/copy-patches.ts","../src/lib/registry/helpers/find-packages-globs.ts","../src/lib/registry/create-packages-registry.ts","../src/lib/registry/list-internal-packages.ts","../src/isolate.ts"],"sourcesContent":["import { createConsola, type ConsolaInstance } from \"consola\";\n\nexport type LogLevel = \"info\" | \"debug\" | \"warn\" | \"error\";\n\n/**\n * The Logger defines an interface that can be used to pass in a different\n * logger object in order to intercept all the logging output.\n */\nexport type Logger = {\n debug(message: unknown, ...args: unknown[]): void;\n info(message: unknown, ...args: unknown[]): void;\n warn(message: unknown, ...args: unknown[]): void;\n error(message: unknown, ...args: unknown[]): void;\n};\n\n/**\n * Map our log levels to consola's numeric levels. Consola levels:\n * 0=fatal/error, 1=warn, 2=log, 3=info, 4=debug, 5=trace\n */\nconst logLevelMap: Record<LogLevel, number> = {\n error: 0,\n warn: 1,\n info: 3,\n debug: 4,\n};\n\nconst _consola: ConsolaInstance = createConsola({\n level: logLevelMap[\"info\"],\n});\n\nlet _customLogger: Logger | null = null;\n\nfunction createMethod(method: keyof Logger) {\n return (message: unknown, ...args: unknown[]) => {\n const target = _customLogger ?? _consola;\n target[method](message, ...args);\n };\n}\n\nconst _logger: Logger = {\n debug: createMethod(\"debug\"),\n info: createMethod(\"info\"),\n warn: createMethod(\"warn\"),\n error: createMethod(\"error\"),\n};\n\nexport function setLogger(logger: Logger) {\n _customLogger = logger;\n return _logger;\n}\n\nexport function setLogLevel(logLevel: LogLevel): Logger {\n _consola.level = logLevelMap[logLevel];\n return _logger;\n}\n\nexport function useLogger() {\n return _logger;\n}\n","export function filterObjectUndefined(object: Record<string, unknown>) {\n return Object.fromEntries(\n Object.entries(object).filter(([_, value]) => value !== undefined),\n );\n}\n","/**\n * Extracts the package name from a package spec like \"chalk@5.3.0\" or\n * \"@firebase/app@1.2.3\"\n */\nexport function getPackageName(packageSpec: string): string {\n if (packageSpec.startsWith(\"@\")) {\n /** Scoped packages: @scope/package@version -> @scope/package */\n const parts = packageSpec.split(\"@\");\n return `@${parts[1] ?? \"\"}`;\n }\n /** Regular packages: package@version -> package */\n return packageSpec.split(\"@\")[0] ?? \"\";\n}\n","import { useLogger } from \"~/lib/logger\";\nimport type { PackageManifest } from \"~/lib/types\";\nimport { getPackageName } from \"./get-package-name\";\n\n/**\n * Filters patched dependencies to only include patches for packages that are\n * present in the target package's dependencies based on dependency type.\n */\nexport function filterPatchedDependencies<T>({\n patchedDependencies,\n targetPackageManifest,\n includeDevDependencies,\n}: {\n patchedDependencies: Record<string, T> | undefined;\n targetPackageManifest: PackageManifest;\n includeDevDependencies: boolean;\n}): Record<string, T> | undefined {\n const log = useLogger();\n if (!patchedDependencies || typeof patchedDependencies !== \"object\") {\n return undefined;\n }\n\n const filteredPatches: Record<string, T> = {};\n let includedCount = 0;\n let excludedCount = 0;\n\n for (const [packageSpec, patchInfo] of Object.entries(patchedDependencies)) {\n const packageName = getPackageName(packageSpec);\n\n /** Check if it's a production dependency */\n if (targetPackageManifest.dependencies?.[packageName]) {\n filteredPatches[packageSpec] = patchInfo;\n includedCount++;\n log.debug(`Including production dependency patch: ${packageSpec}`);\n continue;\n }\n\n /** Check if it's a dev dependency and we should include dev dependencies */\n if (targetPackageManifest.devDependencies?.[packageName]) {\n if (includeDevDependencies) {\n filteredPatches[packageSpec] = patchInfo;\n includedCount++;\n log.debug(`Including dev dependency patch: ${packageSpec}`);\n } else {\n excludedCount++;\n log.debug(`Excluding dev dependency patch: ${packageSpec}`);\n }\n continue;\n }\n\n /** Package not found in dependencies or devDependencies */\n log.debug(\n `Excluding patch: ${packageSpec} (package \"${packageName}\" not in target dependencies)`,\n );\n excludedCount++;\n }\n\n log.debug(\n `Filtered patches: ${includedCount} included, ${excludedCount} excluded`,\n );\n\n return Object.keys(filteredPatches).length > 0 ? filteredPatches : undefined;\n}\n","import { fileURLToPath } from \"url\";\n\n/**\n * Calling context should pass in import.meta.url and the function will return\n * the equivalent of __dirname in Node/CommonJs.\n */\nexport function getDirname(importMetaUrl: string) {\n return fileURLToPath(new URL(\".\", importMetaUrl));\n}\n","type ErrorWithMessage = {\n message: string;\n};\n\nexport function getErrorMessage(error: unknown) {\n return toErrorWithMessage(error).message;\n}\n\nfunction isErrorWithMessage(error: unknown): error is ErrorWithMessage {\n return typeof error === \"object\" && error !== null && \"message\" in error;\n}\n\nfunction toErrorWithMessage(maybeError: unknown): ErrorWithMessage {\n if (isErrorWithMessage(maybeError)) return maybeError;\n\n try {\n return new Error(JSON.stringify(maybeError));\n } catch {\n /**\n * Fallback in case there’s an error in stringify which can happen with\n * circular references.\n */\n return new Error(String(maybeError));\n }\n}\n","import { inspect } from \"node:util\";\n\nexport function inspectValue(value: unknown) {\n return inspect(value, false, 16, true);\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Detect if this is a Rush monorepo. They use a very different structure so\n * there are multiple places where we need to make exceptions based on this.\n */\nexport function isRushWorkspace(workspaceRootDir: string) {\n return fs.existsSync(path.join(workspaceRootDir, \"rush.json\"));\n}\n","import fs from \"fs-extra\";\nimport stripJsonComments from \"strip-json-comments\";\nimport { getErrorMessage } from \"./get-error-message\";\n\n/** @todo Pass in zod schema and validate */\nexport function readTypedJsonSync<T>(filePath: string) {\n try {\n const rawContent = fs.readFileSync(filePath, \"utf-8\");\n const data = JSON.parse(\n stripJsonComments(rawContent, { trailingCommas: true }),\n ) as T;\n return data;\n } catch (err) {\n throw new Error(\n `Failed to read JSON from ${filePath}: ${getErrorMessage(err)}`,\n { cause: err },\n );\n }\n}\n\nexport async function readTypedJson<T>(filePath: string) {\n try {\n const rawContent = await fs.readFile(filePath, \"utf-8\");\n const data = JSON.parse(\n stripJsonComments(rawContent, { trailingCommas: true }),\n ) as T;\n return data;\n } catch (err) {\n throw new Error(\n `Failed to read JSON from ${filePath}: ${getErrorMessage(err)}`,\n { cause: err },\n );\n }\n}\n","import { join } from \"node:path\";\n\nexport function getRootRelativeLogPath(path: string, rootPath: string) {\n const strippedPath = path.replace(rootPath, \"\");\n\n return join(\"(root)\", strippedPath);\n}\n\nexport function getIsolateRelativeLogPath(path: string, isolatePath: string) {\n const strippedPath = path.replace(isolatePath, \"\");\n\n return join(\"(isolate)\", strippedPath);\n}\n","export function getMajorVersion(version: string) {\n return parseInt(version.split(\".\").at(0) ?? \"0\", 10);\n}\n","export const supportedPackageManagerNames = [\n \"pnpm\",\n \"yarn\",\n \"npm\",\n \"bun\",\n] as const;\n\nexport type PackageManagerName = (typeof supportedPackageManagerNames)[number];\n\nexport type PackageManager = {\n name: PackageManagerName;\n version: string;\n majorVersion: number;\n packageManagerString?: string;\n};\n\nexport function getLockfileFileName(name: PackageManagerName) {\n switch (name) {\n case \"bun\":\n return \"bun.lock\";\n case \"pnpm\":\n return \"pnpm-lock.yaml\";\n case \"yarn\":\n return \"yarn.lock\";\n case \"npm\":\n return \"package-lock.json\";\n }\n}\n","import fs from \"fs-extra\";\nimport { execSync } from \"node:child_process\";\nimport path from \"node:path\";\nimport { getErrorMessage } from \"~/lib/utils\";\nimport { getMajorVersion } from \"~/lib/utils/get-major-version\";\nimport type { PackageManager, PackageManagerName } from \"../names\";\nimport { getLockfileFileName, supportedPackageManagerNames } from \"../names\";\n\nexport function inferFromFiles(workspaceRoot: string): PackageManager {\n for (const name of supportedPackageManagerNames) {\n const lockfileName = getLockfileFileName(name);\n\n if (fs.existsSync(path.join(workspaceRoot, lockfileName))) {\n try {\n const version = getVersion(name);\n\n return { name, version, majorVersion: getMajorVersion(version) };\n } catch (err) {\n throw new Error(\n `Failed to find package manager version for ${name}: ${getErrorMessage(err)}`,\n { cause: err },\n );\n }\n }\n }\n\n /** If no lockfile was found, it could be that there is an npm shrinkwrap file. */\n if (fs.existsSync(path.join(workspaceRoot, \"npm-shrinkwrap.json\"))) {\n const version = getVersion(\"npm\");\n\n return { name: \"npm\", version, majorVersion: getMajorVersion(version) };\n }\n\n throw new Error(`Failed to detect package manager`);\n}\n\nexport function getVersion(packageManagerName: PackageManagerName): string {\n const buffer = execSync(`${packageManagerName} --version`);\n return buffer.toString().trim();\n}\n","import fs from \"fs-extra\";\nimport assert from \"node:assert\";\nimport path from \"node:path\";\nimport { useLogger } from \"~/lib/logger\";\nimport { getMajorVersion } from \"~/lib/utils/get-major-version\";\nimport type { PackageManifest } from \"../../types\";\nimport { readTypedJsonSync } from \"../../utils\";\nimport type { PackageManagerName } from \"../names\";\nimport { getLockfileFileName, supportedPackageManagerNames } from \"../names\";\n\nexport function inferFromManifest(workspaceRoot: string) {\n const log = useLogger();\n\n const { packageManager: packageManagerString } =\n readTypedJsonSync<PackageManifest>(\n path.join(workspaceRoot, \"package.json\"),\n );\n\n if (!packageManagerString) {\n log.debug(\"No packageManager field found in root manifest\");\n return;\n }\n\n const [name, version = \"*\"] = packageManagerString.split(\"@\") as [\n PackageManagerName,\n string,\n ];\n\n assert(\n supportedPackageManagerNames.includes(name),\n `Package manager \"${name}\" is not currently supported`,\n );\n\n const lockfileName = getLockfileFileName(name);\n\n assert(\n fs.existsSync(path.join(workspaceRoot, lockfileName)),\n `Manifest declares ${name} to be the packageManager, but failed to find ${lockfileName} in workspace root`,\n );\n\n return {\n name,\n version,\n majorVersion: getMajorVersion(version),\n packageManagerString,\n };\n}\n","import path from \"node:path\";\nimport { isRushWorkspace } from \"../utils/is-rush-workspace\";\nimport { inferFromFiles, inferFromManifest } from \"./helpers\";\nimport type { PackageManager } from \"./names\";\n\nexport * from \"./names\";\n\nlet packageManager: PackageManager | undefined;\n\nexport function usePackageManager() {\n if (!packageManager) {\n throw Error(\n \"No package manager detected. Make sure to call detectPackageManager() before usePackageManager()\",\n );\n }\n\n return packageManager;\n}\n\n/**\n * First we check if the package manager is declared in the manifest. If it is,\n * we get the name and version from there. Otherwise we'll search for the\n * different lockfiles and ask the OS to report the installed version.\n */\nexport function detectPackageManager(workspaceRootDir: string): PackageManager {\n if (isRushWorkspace(workspaceRootDir)) {\n packageManager = inferFromFiles(\n path.join(workspaceRootDir, \"common/config/rush\"),\n );\n } else {\n /**\n * Disable infer from manifest for now. I doubt it is useful after all but\n * I'll keep the code as a reminder.\n */\n packageManager =\n inferFromManifest(workspaceRootDir) ?? inferFromFiles(workspaceRootDir);\n }\n\n return packageManager;\n}\n\nexport function shouldUsePnpmPack() {\n const { name, majorVersion } = usePackageManager();\n\n return name === \"pnpm\" && majorVersion >= 8;\n}\n","import assert from \"node:assert\";\nimport { exec } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { useLogger } from \"../logger\";\nimport { shouldUsePnpmPack } from \"../package-manager\";\nimport { getErrorMessage } from \"./get-error-message\";\n\nexport async function pack(srcDir: string, dstDir: string) {\n const log = useLogger();\n\n const execOptions = {\n maxBuffer: 10 * 1024 * 1024,\n };\n\n const previousCwd = process.cwd();\n process.chdir(srcDir);\n\n /**\n * PNPM pack seems to be a lot faster than NPM pack, so when PNPM is detected\n * we use that instead.\n */\n const stdout = shouldUsePnpmPack()\n ? await new Promise<string>((resolve, reject) => {\n exec(\n `pnpm pack --pack-destination \"${dstDir}\"`,\n execOptions,\n (err, stdout) => {\n if (err) {\n log.error(getErrorMessage(err));\n return reject(err);\n }\n\n resolve(stdout);\n },\n );\n })\n : await new Promise<string>((resolve, reject) => {\n exec(\n `npm pack --pack-destination \"${dstDir}\"`,\n execOptions,\n (err, stdout) => {\n if (err) {\n return reject(err);\n }\n\n resolve(stdout);\n },\n );\n });\n\n const lastLine = stdout.trim().split(\"\\n\").at(-1);\n\n assert(lastLine, `Failed to parse last line from stdout: ${stdout.trim()}`);\n\n const fileName = path.basename(lastLine);\n\n assert(fileName, `Failed to parse file name from: ${lastLine}`);\n\n const filePath = path.join(dstDir, fileName);\n\n if (!fs.existsSync(filePath)) {\n log.error(\n `The response from pack could not be resolved to an existing file: ${filePath}`,\n );\n } else {\n log.debug(`Packed (temp)/${fileName}`);\n }\n\n process.chdir(previousCwd);\n\n /**\n * Return the path anyway even if it doesn't validate. A later stage will wait\n * for the file to occur still. Not sure if this makes sense. Maybe we should\n * stop at the validation error...\n */\n return filePath;\n}\n","import fs from \"fs-extra\";\nimport tar from \"tar-fs\";\nimport { createGunzip } from \"zlib\";\n\nexport async function unpack(filePath: string, unpackDir: string) {\n await new Promise<void>((resolve, reject) => {\n fs.createReadStream(filePath)\n .pipe(createGunzip())\n .pipe(tar.extract(unpackDir))\n .on(\"finish\", () => resolve())\n .on(\"error\", (err) => reject(err));\n });\n}\n","import fs from \"fs-extra\";\nimport yaml from \"yaml\";\nimport { getErrorMessage } from \"./get-error-message\";\n\nexport function readTypedYamlSync<T>(filePath: string) {\n try {\n const rawContent = fs.readFileSync(filePath, \"utf-8\");\n const data = yaml.parse(rawContent);\n /** @todo Add some zod validation maybe */\n return data as T;\n } catch (err) {\n throw new Error(\n `Failed to read YAML from ${filePath}: ${getErrorMessage(err)}`,\n { cause: err },\n );\n }\n}\n\nexport function writeTypedYamlSync<T>(filePath: string, content: T) {\n /** @todo Add some zod validation maybe */\n fs.writeFileSync(filePath, yaml.stringify(content), \"utf-8\");\n}\n","import { execFileSync } from \"node:child_process\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { isEmpty } from \"remeda\";\nimport { type LogLevel, setLogLevel, useLogger } from \"./logger\";\nimport { inspectValue, readTypedJsonSync } from \"./utils\";\n\nexport type IsolateConfigResolved = {\n buildDirName?: string;\n includeDevDependencies: boolean;\n isolateDirName: string;\n logLevel: LogLevel;\n targetPackagePath?: string;\n tsconfigPath: string;\n workspacePackages?: string[];\n workspaceRoot: string;\n forceNpm: boolean;\n pickFromScripts?: string[];\n omitFromScripts?: string[];\n omitPackageManager?: boolean;\n};\n\nexport type IsolateConfig = Partial<IsolateConfigResolved>;\n\nconst configDefaults: IsolateConfigResolved = {\n buildDirName: undefined,\n includeDevDependencies: false,\n isolateDirName: \"isolate\",\n logLevel: \"info\",\n targetPackagePath: undefined,\n tsconfigPath: \"./tsconfig.json\",\n workspacePackages: undefined,\n workspaceRoot: \"../..\",\n forceNpm: false,\n pickFromScripts: undefined,\n omitFromScripts: undefined,\n omitPackageManager: false,\n};\n\nconst validConfigKeys = Object.keys(configDefaults);\nconst CONFIG_FILE_NAME_TS = \"isolate.config.ts\";\nconst CONFIG_FILE_NAME_JS = \"isolate.config.js\";\nconst CONFIG_FILE_NAME_JSON = \"isolate.config.json\";\n\n/**\n * Load a JS or TS config file by spawning a Node subprocess. For TS files,\n * --experimental-strip-types is added so Node can handle TypeScript natively.\n * This keeps the function synchronous while allowing us to import the module.\n */\nconst CONFIG_JSON_DELIMITER = \"__ISOLATE_CONFIG_JSON__\";\n\nfunction loadModuleConfig(filePath: string): IsolateConfig {\n const fileUrl = pathToFileURL(filePath).href;\n const isTypeScript = filePath.endsWith(\".ts\");\n const script = `import(process.argv[1])\n .then(m => {\n if (m.default === undefined) {\n process.stderr.write(\"Config file has no default export\");\n process.exit(1);\n }\n process.stdout.write(\"${CONFIG_JSON_DELIMITER}\" + JSON.stringify(m.default) + \"${CONFIG_JSON_DELIMITER}\");\n })\n .catch(err => {\n process.stderr.write(String(err));\n process.exit(1);\n })`;\n\n try {\n const result = execFileSync(\n process.execPath,\n [\n ...(isTypeScript ? [\"--experimental-strip-types\"] : []),\n \"--no-warnings\",\n \"--input-type=module\",\n \"-e\",\n script,\n fileUrl,\n ],\n { encoding: \"utf8\" },\n );\n\n const jsonMatch = result.split(CONFIG_JSON_DELIMITER)[1];\n\n if (jsonMatch === undefined) {\n throw new Error(\"Failed to extract config JSON from subprocess output\");\n }\n\n const parsed = JSON.parse(jsonMatch);\n\n if (\n typeof parsed !== \"object\" ||\n parsed === null ||\n Array.isArray(parsed)\n ) {\n throw new Error(\n `Expected default export to be an object, got ${typeof parsed}`,\n );\n }\n\n return parsed;\n } catch (error) {\n const stderr =\n error instanceof Error && \"stderr\" in error\n ? String(error.stderr).trim()\n : \"\";\n const detail = stderr || (error instanceof Error ? error.message : \"\");\n throw new Error(\n `Failed to load config from ${filePath}${detail ? `: ${detail}` : \"\"}`,\n { cause: error },\n );\n }\n}\n\nexport function loadConfigFromFile(): IsolateConfig {\n const log = useLogger();\n const cwd = process.cwd();\n const tsConfigPath = path.join(cwd, CONFIG_FILE_NAME_TS);\n const jsConfigPath = path.join(cwd, CONFIG_FILE_NAME_JS);\n const jsonConfigPath = path.join(cwd, CONFIG_FILE_NAME_JSON);\n\n const tsExists = fs.existsSync(tsConfigPath);\n const jsExists = fs.existsSync(jsConfigPath);\n const jsonExists = fs.existsSync(jsonConfigPath);\n\n const existingFiles = [\n tsExists && CONFIG_FILE_NAME_TS,\n jsExists && CONFIG_FILE_NAME_JS,\n jsonExists && CONFIG_FILE_NAME_JSON,\n ].filter(Boolean);\n\n if (existingFiles.length > 1) {\n log.warn(\n `Found multiple config files: ${existingFiles.join(\", \")}. Using ${existingFiles[0]}.`,\n );\n }\n\n if (tsExists) {\n return loadModuleConfig(tsConfigPath);\n }\n\n if (jsExists) {\n return loadModuleConfig(jsConfigPath);\n }\n\n if (jsonExists) {\n return readTypedJsonSync<IsolateConfig>(jsonConfigPath);\n }\n\n return {};\n}\n\n/** Helper for type-safe configuration in isolate.config.ts files. */\nexport function defineConfig(config: IsolateConfig): IsolateConfig {\n return config;\n}\n\nfunction validateConfig(config: IsolateConfig) {\n const log = useLogger();\n const foreignKeys = Object.keys(config).filter(\n (key) => !validConfigKeys.includes(key),\n );\n\n if (!isEmpty(foreignKeys)) {\n log.warn(`Found invalid config settings:`, foreignKeys.join(\", \"));\n }\n}\n\n/**\n * Resolve the target package directory and workspace root directory from the\n * configuration. When targetPackagePath is set, the config is assumed to live\n * at the workspace root. Otherwise it lives in the target package directory.\n */\nexport function resolveWorkspacePaths(config: IsolateConfigResolved) {\n const targetPackageDir = config.targetPackagePath\n ? path.join(process.cwd(), config.targetPackagePath)\n : process.cwd();\n\n const workspaceRootDir = config.targetPackagePath\n ? process.cwd()\n : path.join(targetPackageDir, config.workspaceRoot);\n\n return { targetPackageDir, workspaceRootDir };\n}\n\nexport function resolveConfig(\n initialConfig?: IsolateConfig,\n): IsolateConfigResolved {\n setLogLevel(process.env.DEBUG_ISOLATE_CONFIG ? \"debug\" : \"info\");\n const log = useLogger();\n\n const userConfig = initialConfig ?? loadConfigFromFile();\n\n if (initialConfig) {\n log.debug(`Using user defined config:`, inspectValue(initialConfig));\n } else {\n log.debug(`Loaded config from file`);\n }\n\n validateConfig(userConfig);\n\n if (userConfig.logLevel) {\n setLogLevel(userConfig.logLevel);\n }\n\n const config = {\n ...configDefaults,\n ...userConfig,\n } satisfies IsolateConfigResolved;\n\n log.debug(\"Using configuration:\", inspectValue(config));\n\n return config;\n}\n","import Config from \"@npmcli/config\";\nimport defaults from \"@npmcli/config/lib/definitions/index.js\";\n\nexport async function loadNpmConfig({ npmPath }: { npmPath: string }) {\n const config = new Config({\n npmPath,\n definitions: defaults.definitions,\n shorthands: defaults.shorthands,\n flatten: defaults.flatten,\n });\n\n await config.load();\n\n return config;\n}\n","import Arborist from \"@npmcli/arborist\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { useLogger } from \"~/lib/logger\";\nimport { getErrorMessage } from \"~/lib/utils\";\nimport { loadNpmConfig } from \"./load-npm-config\";\n\n/**\n * Generate an isolated / pruned lockfile, based on the contents of installed\n * node_modules from the monorepo root plus the adapted package manifest in the\n * isolate directory.\n */\nexport async function generateNpmLockfile({\n workspaceRootDir,\n isolateDir,\n}: {\n workspaceRootDir: string;\n isolateDir: string;\n}) {\n const log = useLogger();\n\n log.debug(\"Generating NPM lockfile...\");\n\n const nodeModulesPath = path.join(workspaceRootDir, \"node_modules\");\n\n try {\n if (!fs.existsSync(nodeModulesPath)) {\n throw new Error(`Failed to find node_modules at ${nodeModulesPath}`);\n }\n\n const config = await loadNpmConfig({ npmPath: workspaceRootDir });\n\n const arborist = new Arborist({\n path: isolateDir,\n ...config.flat,\n });\n\n const { meta } = await arborist.buildIdealTree();\n\n meta?.commit();\n\n const lockfilePath = path.join(isolateDir, \"package-lock.json\");\n\n await fs.writeFile(lockfilePath, String(meta));\n\n log.debug(\"Created lockfile at\", lockfilePath);\n } catch (err) {\n log.error(`Failed to generate lockfile: ${getErrorMessage(err)}`);\n throw err;\n }\n}\n","import path from \"node:path\";\nimport type {\n ProjectSnapshot,\n ResolvedDependencies,\n} from \"pnpm_lockfile_file_v8\";\n\n/** Convert dependency links */\nexport function pnpmMapImporter(\n importerPath: string,\n { dependencies, devDependencies, ...rest }: ProjectSnapshot,\n {\n includeDevDependencies,\n directoryByPackageName,\n }: {\n includeDevDependencies: boolean;\n directoryByPackageName: { [packageName: string]: string };\n },\n): ProjectSnapshot {\n return {\n dependencies: dependencies\n ? pnpmMapDependenciesLinks(\n importerPath,\n dependencies,\n directoryByPackageName,\n )\n : undefined,\n devDependencies:\n includeDevDependencies && devDependencies\n ? pnpmMapDependenciesLinks(\n importerPath,\n devDependencies,\n directoryByPackageName,\n )\n : undefined,\n ...rest,\n };\n}\n\n/**\n * Remap internal dependency links to point to the isolated directory structure,\n * and remove link: entries for non-internal packages that won't exist in the\n * isolated output.\n */\nfunction pnpmMapDependenciesLinks(\n importerPath: string,\n def: ResolvedDependencies,\n directoryByPackageName: { [packageName: string]: string },\n): ResolvedDependencies {\n return Object.fromEntries(\n Object.entries(def).flatMap(([key, value]) => {\n if (!value.startsWith(\"link:\")) {\n return [[key, value]];\n }\n\n const directory = directoryByPackageName[key];\n\n /**\n * Remove entries for packages not in the internal dependencies map. These\n * are external packages that happen to be linked via the link: protocol\n * and won't exist in the isolated output.\n */\n if (directory === undefined) {\n return [];\n }\n\n /** Replace backslashes with forward slashes to support Windows Git Bash */\n const relativePath = path\n .relative(importerPath, directory)\n .replace(path.sep, path.posix.sep);\n\n const linkValue = relativePath.startsWith(\".\")\n ? `link:${relativePath}`\n : `link:./${relativePath}`;\n\n return [[key, linkValue]];\n }),\n );\n}\n","import assert from \"node:assert\";\nimport path from \"node:path\";\nimport {\n getLockfileImporterId as getLockfileImporterId_v8,\n readWantedLockfile as readWantedLockfile_v8,\n writeWantedLockfile as writeWantedLockfile_v8,\n} from \"pnpm_lockfile_file_v8\";\nimport {\n getLockfileImporterId as getLockfileImporterId_v9,\n readWantedLockfile as readWantedLockfile_v9,\n writeWantedLockfile as writeWantedLockfile_v9,\n} from \"pnpm_lockfile_file_v9\";\nimport { pruneLockfile as pruneLockfile_v8 } from \"pnpm_prune_lockfile_v8\";\nimport { pruneLockfile as pruneLockfile_v9 } from \"pnpm_prune_lockfile_v9\";\nimport { pick } from \"remeda\";\nimport { useLogger } from \"~/lib/logger\";\nimport type { PackageManifest, PackagesRegistry, PatchFile } from \"~/lib/types\";\nimport { getErrorMessage, isRushWorkspace } from \"~/lib/utils\";\nimport { pnpmMapImporter } from \"./pnpm-map-importer\";\n\nexport async function generatePnpmLockfile({\n workspaceRootDir,\n targetPackageDir,\n isolateDir,\n internalDepPackageNames,\n packagesRegistry,\n targetPackageManifest,\n majorVersion,\n includeDevDependencies,\n patchedDependencies,\n}: {\n workspaceRootDir: string;\n targetPackageDir: string;\n isolateDir: string;\n internalDepPackageNames: string[];\n packagesRegistry: PackagesRegistry;\n targetPackageManifest: PackageManifest;\n majorVersion: number;\n includeDevDependencies: boolean;\n /** Pre-computed patched dependencies with transformed paths from copyPatches */\n patchedDependencies?: Record<string, PatchFile>;\n}) {\n /**\n * For now we will assume that the lockfile format might not change in the\n * versions after 9, because we might get lucky. If it does change, things\n * would break either way.\n */\n const useVersion9 = majorVersion >= 9;\n\n const log = useLogger();\n\n log.debug(\"Generating PNPM lockfile...\");\n\n try {\n const isRush = isRushWorkspace(workspaceRootDir);\n\n const lockfile = useVersion9\n ? await readWantedLockfile_v9(\n isRush\n ? path.join(workspaceRootDir, \"common/config/rush\")\n : workspaceRootDir,\n {\n ignoreIncompatible: false,\n },\n )\n : await readWantedLockfile_v8(\n isRush\n ? path.join(workspaceRootDir, \"common/config/rush\")\n : workspaceRootDir,\n {\n ignoreIncompatible: false,\n },\n );\n\n assert(lockfile, `No input lockfile found at ${workspaceRootDir}`);\n\n const targetImporterId = useVersion9\n ? getLockfileImporterId_v9(workspaceRootDir, targetPackageDir)\n : getLockfileImporterId_v8(workspaceRootDir, targetPackageDir);\n\n const directoryByPackageName = Object.fromEntries(\n internalDepPackageNames.map((name) => {\n const pkg = packagesRegistry[name];\n assert(pkg, `Package ${name} not found in packages registry`);\n\n return [name, pkg.rootRelativeDir];\n }),\n );\n\n const relevantImporterIds = [\n targetImporterId,\n /**\n * The directory paths happen to correspond with what PNPM calls the\n * importer ids in the context of a lockfile.\n */\n ...Object.values(directoryByPackageName),\n /**\n * Split the path by the OS separator and join it back with the POSIX\n * separator.\n *\n * The importerIds are built from directory names, so Windows Git Bash\n * environments will have double backslashes in their ids:\n * \"packages\\common\" vs. \"packages/common\". Without this split & join, any\n * packages not on the top-level will have ill-formatted importerIds and\n * their entries will be missing from the lockfile.importers list.\n */\n ].map((x) => x.split(path.sep).join(path.posix.sep));\n\n log.debug(\"Relevant importer ids:\", relevantImporterIds);\n\n /**\n * In a Rush workspace the original lockfile is not in the root, so the\n * importerIds have to be prefixed with `../../`, but that's not how they\n * should be stored in the isolated lockfile, so we use the prefixed ids\n * only for parsing.\n */\n const relevantImporterIdsWithPrefix = relevantImporterIds.map((x) =>\n isRush ? `../../${x}` : x,\n );\n\n lockfile.importers = Object.fromEntries(\n Object.entries(\n pick(lockfile.importers, relevantImporterIdsWithPrefix),\n ).map(([prefixedImporterId, importer]) => {\n const importerId = isRush\n ? prefixedImporterId.replace(\"../../\", \"\")\n : prefixedImporterId;\n\n if (importerId === targetImporterId) {\n log.debug(\"Setting target package importer on root\");\n\n return [\n \".\",\n pnpmMapImporter(\".\", importer, {\n includeDevDependencies,\n directoryByPackageName,\n }),\n ];\n }\n\n log.debug(\"Setting internal package importer:\", importerId);\n\n return [\n importerId,\n pnpmMapImporter(importerId, importer, {\n includeDevDependencies: false,\n directoryByPackageName,\n }),\n ];\n }),\n );\n\n log.debug(\"Pruning the lockfile\");\n\n const prunedLockfile = useVersion9\n ? pruneLockfile_v9(lockfile, targetPackageManifest, \".\")\n : pruneLockfile_v8(lockfile, targetPackageManifest, \".\");\n\n /** Pruning seems to remove the overrides from the lockfile */\n if (lockfile.overrides) {\n prunedLockfile.overrides = lockfile.overrides;\n }\n\n /** Add packageExtensionsChecksum back to the pruned lockfile if present */\n if (lockfile.packageExtensionsChecksum) {\n prunedLockfile.packageExtensionsChecksum =\n lockfile.packageExtensionsChecksum;\n }\n\n /**\n * Use pre-computed patched dependencies with transformed paths. The paths\n * are already adapted by copyPatches to match the isolated directory\n * structure, preserving the original folder structure (not flattened).\n */\n if (useVersion9) {\n await writeWantedLockfile_v9(isolateDir, {\n ...prunedLockfile,\n patchedDependencies,\n });\n } else {\n await writeWantedLockfile_v8(isolateDir, {\n ...prunedLockfile,\n patchedDependencies,\n });\n }\n\n log.debug(\"Created lockfile at\", path.join(isolateDir, \"pnpm-lock.yaml\"));\n } catch (err) {\n log.error(`Failed to generate lockfile: ${getErrorMessage(err)}`);\n throw err;\n }\n}\n","import fs from \"fs-extra\";\nimport { execSync } from \"node:child_process\";\nimport path from \"node:path\";\nimport { useLogger } from \"~/lib/logger\";\nimport { getErrorMessage, isRushWorkspace } from \"~/lib/utils\";\n\n/**\n * Generate an isolated / pruned lockfile, based on the existing lockfile from\n * the monorepo root plus the adapted package manifest in the isolate\n * directory.\n */\nexport async function generateYarnLockfile({\n workspaceRootDir,\n isolateDir,\n}: {\n workspaceRootDir: string;\n isolateDir: string;\n}) {\n const log = useLogger();\n\n log.debug(\"Generating Yarn lockfile...\");\n\n const origLockfilePath = isRushWorkspace(workspaceRootDir)\n ? path.join(workspaceRootDir, \"common/config/rush\", \"yarn.lock\")\n : path.join(workspaceRootDir, \"yarn.lock\");\n\n const newLockfilePath = path.join(isolateDir, \"yarn.lock\");\n\n if (!fs.existsSync(origLockfilePath)) {\n throw new Error(`Failed to find lockfile at ${origLockfilePath}`);\n }\n\n log.debug(`Copy original yarn.lock to the isolate output`);\n\n try {\n await fs.copyFile(origLockfilePath, newLockfilePath);\n\n /**\n * Running install with the original lockfile in the same directory will\n * generate a pruned version of the lockfile.\n */\n log.debug(`Running local install`);\n execSync(`yarn install --cwd ${isolateDir}`);\n\n log.debug(\"Generated lockfile at\", newLockfilePath);\n } catch (err) {\n log.error(`Failed to generate lockfile: ${getErrorMessage(err)}`);\n throw err;\n }\n}\n","import type { IsolateConfigResolved } from \"../config\";\nimport { useLogger } from \"../logger\";\nimport { usePackageManager } from \"../package-manager\";\nimport type { PackageManifest, PackagesRegistry, PatchFile } from \"../types\";\nimport {\n generateNpmLockfile,\n generatePnpmLockfile,\n generateYarnLockfile,\n} from \"./helpers\";\n\n/**\n * Adapt the lockfile and write it to the isolate directory. Because we keep the\n * structure of packages in the isolate directory the same as they were in the\n * monorepo, the lockfile is largely still correct. The only things that need to\n * be done is to remove the root dependencies and devDependencies, and rename\n * the path to the target package to act as the new root.\n */\nexport async function processLockfile({\n workspaceRootDir,\n packagesRegistry,\n isolateDir,\n internalDepPackageNames,\n targetPackageDir,\n targetPackageManifest,\n patchedDependencies,\n config,\n}: {\n workspaceRootDir: string;\n packagesRegistry: PackagesRegistry;\n isolateDir: string;\n internalDepPackageNames: string[];\n targetPackageDir: string;\n targetPackageName: string;\n targetPackageManifest: PackageManifest;\n /** Pre-computed patched dependencies with transformed paths from copyPatches */\n patchedDependencies?: Record<string, PatchFile>;\n config: IsolateConfigResolved;\n}) {\n const log = useLogger();\n\n if (config.forceNpm) {\n log.debug(\"Forcing to use NPM for isolate output\");\n\n await generateNpmLockfile({\n workspaceRootDir,\n isolateDir,\n });\n\n return true;\n }\n\n const { name, majorVersion } = usePackageManager();\n let usedFallbackToNpm = false;\n\n switch (name) {\n case \"npm\": {\n await generateNpmLockfile({\n workspaceRootDir,\n isolateDir,\n });\n\n break;\n }\n case \"yarn\": {\n if (majorVersion === 1) {\n await generateYarnLockfile({\n workspaceRootDir,\n isolateDir,\n });\n } else {\n log.warn(\n \"Detected modern version of Yarn. Using NPM lockfile fallback.\",\n );\n\n await generateNpmLockfile({\n workspaceRootDir,\n isolateDir,\n });\n\n usedFallbackToNpm = true;\n }\n\n break;\n }\n case \"pnpm\": {\n await generatePnpmLockfile({\n workspaceRootDir,\n targetPackageDir,\n isolateDir,\n internalDepPackageNames,\n packagesRegistry,\n targetPackageManifest,\n majorVersion,\n includeDevDependencies: config.includeDevDependencies,\n patchedDependencies,\n });\n break;\n }\n case \"bun\": {\n log.warn(\n `Ouput lockfiles for Bun are not yet supported. Using NPM for output`,\n );\n await generateNpmLockfile({\n workspaceRootDir,\n isolateDir,\n });\n\n usedFallbackToNpm = true;\n break;\n }\n default:\n log.warn(\n `Unexpected package manager ${name as string}. Using NPM for output`,\n );\n await generateNpmLockfile({\n workspaceRootDir,\n isolateDir,\n });\n\n usedFallbackToNpm = true;\n }\n\n return usedFallbackToNpm;\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport type { PackageManifest } from \"../types\";\nimport { readTypedJson } from \"../utils\";\n\nexport async function readManifest(packageDir: string) {\n return readTypedJson<PackageManifest>(path.join(packageDir, \"package.json\"));\n}\n\nexport async function writeManifest(\n outputDir: string,\n manifest: PackageManifest,\n) {\n await fs.writeFile(\n path.join(outputDir, \"package.json\"),\n JSON.stringify(manifest, null, 2),\n );\n}\n","import { got } from \"get-or-throw\";\nimport path from \"node:path\";\nimport { useLogger } from \"../../logger\";\nimport type { PackagesRegistry } from \"../../types\";\n\nexport function patchInternalEntries(\n dependencies: Record<string, string>,\n packagesRegistry: PackagesRegistry,\n parentRootRelativeDir?: string,\n) {\n const log = useLogger();\n const allWorkspacePackageNames = Object.keys(packagesRegistry);\n\n return Object.fromEntries(\n Object.entries(dependencies).map(([key, value]) => {\n if (allWorkspacePackageNames.includes(key)) {\n const def = got(packagesRegistry, key);\n\n /**\n * When nested internal dependencies are used (internal packages linking\n * to other internal packages), the parentRootRelativeDir will be passed\n * in, and we store the relative path to the isolate/packages\n * directory.\n *\n * For consistency we also write the other file paths starting with ./,\n * but it doesn't seem to be necessary for any package manager.\n */\n const relativePath = parentRootRelativeDir\n ? path.relative(parentRootRelativeDir, `./${def.rootRelativeDir}`)\n : `./${def.rootRelativeDir}`;\n\n const linkPath = `file:${relativePath}`;\n\n log.debug(`Linking dependency ${key} to ${linkPath}`);\n\n return [key, linkPath];\n } else {\n return [key, value];\n }\n }),\n );\n}\n","import type { PackageManifest, PackagesRegistry } from \"~/lib/types\";\nimport { patchInternalEntries } from \"./patch-internal-entries\";\n\n/**\n * Replace the workspace version specifiers for internal dependency with file:\n * paths. Not needed for PNPM (because we configure the isolated output as a\n * workspace), but maybe still for NPM and Yarn.\n */\nexport function adaptManifestInternalDeps({\n manifest,\n packagesRegistry,\n parentRootRelativeDir,\n}: {\n manifest: PackageManifest;\n packagesRegistry: PackagesRegistry;\n parentRootRelativeDir?: string;\n}): PackageManifest {\n const { dependencies, devDependencies } = manifest;\n\n return {\n ...manifest,\n dependencies: dependencies\n ? patchInternalEntries(\n dependencies,\n packagesRegistry,\n parentRootRelativeDir,\n )\n : undefined,\n devDependencies: devDependencies\n ? patchInternalEntries(\n devDependencies,\n packagesRegistry,\n parentRootRelativeDir,\n )\n : undefined,\n };\n}\n","import path from \"node:path\";\nimport { useLogger } from \"~/lib/logger\";\nimport type { PackageManifest } from \"~/lib/types\";\nimport { readTypedJson } from \"~/lib/utils\";\n\n/**\n * Resolves catalog dependencies by replacing \"catalog:\" specifiers with their\n * actual versions from the root package.json catalog field.\n *\n * Supports both pnpm and Bun catalog formats:\n *\n * - Pnpm: catalog at root level\n * - Bun: catalog or catalogs at root level, or workspaces.catalog\n */\nexport async function resolveCatalogDependencies(\n dependencies: Record<string, string> | undefined,\n workspaceRootDir: string,\n): Promise<Record<string, string> | undefined> {\n if (!dependencies) {\n return undefined;\n }\n\n const log = useLogger();\n const rootManifestPath = path.join(workspaceRootDir, \"package.json\");\n const rootManifest = await readTypedJson<\n PackageManifest & {\n catalog?: Record<string, string>;\n catalogs?: Record<string, Record<string, string>>;\n workspaces?: {\n catalog?: Record<string, string>;\n catalogs?: Record<string, Record<string, string>>;\n };\n }\n >(rootManifestPath);\n\n // Try to find catalog in various locations (pnpm and Bun formats)\n const flatCatalog = rootManifest.catalog || rootManifest.workspaces?.catalog;\n const nestedCatalogs =\n rootManifest.catalogs || rootManifest.workspaces?.catalogs;\n\n if (!flatCatalog && !nestedCatalogs) {\n // No catalog found, return dependencies as-is\n return dependencies;\n }\n\n const resolved = { ...dependencies };\n\n for (const [packageName, specifier] of Object.entries(dependencies)) {\n // Check if this is a catalog dependency\n if (specifier === \"catalog:\" || specifier.startsWith(\"catalog:\")) {\n let catalogVersion: string | undefined;\n\n if (specifier === \"catalog:\") {\n // Simple catalog reference - use package name as key\n catalogVersion = flatCatalog?.[packageName];\n } else {\n // Catalog group reference (e.g., \"catalog:group1\")\n const groupName = specifier.slice(8);\n catalogVersion = nestedCatalogs?.[groupName]?.[packageName];\n }\n\n if (catalogVersion) {\n log.debug(\n `Resolving catalog dependency ${packageName}: \"${specifier}\" -> \"${catalogVersion}\"`,\n );\n resolved[packageName] = catalogVersion;\n } else {\n log.warn(\n `Catalog dependency ${packageName} references \"${specifier}\" but it's not found in the catalog. Keeping original specifier.`,\n );\n }\n }\n }\n\n return resolved;\n}\n","import { got } from \"get-or-throw\";\nimport path from \"node:path\";\nimport { omit } from \"remeda\";\nimport { usePackageManager } from \"~/lib/package-manager\";\nimport type { PackagesRegistry } from \"~/lib/types\";\nimport { writeManifest } from \"../io\";\nimport { adaptManifestInternalDeps } from \"./adapt-manifest-internal-deps\";\nimport { resolveCatalogDependencies } from \"./resolve-catalog-dependencies\";\n\n/**\n * Adapt the manifest files of all the isolated internal packages (excluding the\n * target package), so that their dependencies point to the other isolated\n * packages in the same folder.\n */\nexport async function adaptInternalPackageManifests({\n internalPackageNames,\n packagesRegistry,\n isolateDir,\n forceNpm,\n workspaceRootDir,\n}: {\n internalPackageNames: string[];\n packagesRegistry: PackagesRegistry;\n isolateDir: string;\n forceNpm: boolean;\n workspaceRootDir: string;\n}) {\n const packageManager = usePackageManager();\n\n await Promise.all(\n internalPackageNames.map(async (packageName) => {\n const { manifest, rootRelativeDir } = got(packagesRegistry, packageName);\n\n /** Dev dependencies and scripts are never included for internal deps */\n const strippedManifest = omit(manifest, [\"scripts\", \"devDependencies\"]);\n\n /** Resolve catalog dependencies before adapting internal deps */\n const manifestWithResolvedCatalogs = {\n ...strippedManifest,\n dependencies: await resolveCatalogDependencies(\n strippedManifest.dependencies,\n workspaceRootDir,\n ),\n };\n\n const outputManifest =\n packageManager.name === \"pnpm\" && !forceNpm\n ? /**\n * For PNPM the output itself is a workspace so we can preserve the specifiers\n * with \"workspace:*\" in the output manifest.\n */\n manifestWithResolvedCatalogs\n : /** For other package managers we replace the links to internal dependencies */\n adaptManifestInternalDeps({\n manifest: manifestWithResolvedCatalogs,\n packagesRegistry,\n parentRootRelativeDir: rootRelativeDir,\n });\n\n await writeManifest(\n path.join(isolateDir, rootRelativeDir),\n outputManifest,\n );\n }),\n );\n}\n","import type { ProjectManifest, PnpmSettings } from \"@pnpm/types\";\nimport path from \"path\";\nimport type { PackageManifest } from \"~/lib/types\";\nimport { isRushWorkspace, readTypedJson } from \"~/lib/utils\";\n\n/**\n * Adopts the `pnpm` fields from the root package manifest. Currently it takes\n * overrides, onlyBuiltDependencies, and ignoredBuiltDependencies, because these\n * are typically workspace-level configuration settings.\n */\nexport async function adoptPnpmFieldsFromRoot(\n targetPackageManifest: PackageManifest,\n workspaceRootDir: string,\n): Promise<PackageManifest> {\n if (isRushWorkspace(workspaceRootDir)) {\n return targetPackageManifest;\n }\n\n const rootPackageManifest = await readTypedJson<ProjectManifest>(\n path.join(workspaceRootDir, \"package.json\"),\n );\n\n const { overrides, onlyBuiltDependencies, ignoredBuiltDependencies } =\n rootPackageManifest.pnpm || {};\n\n /** If no pnpm fields are present, return the original manifest */\n if (!overrides && !onlyBuiltDependencies && !ignoredBuiltDependencies) {\n return targetPackageManifest;\n }\n\n const pnpmConfig: Partial<PnpmSettings> = {};\n\n if (overrides) {\n pnpmConfig.overrides = overrides;\n }\n\n if (onlyBuiltDependencies) {\n pnpmConfig.onlyBuiltDependencies = onlyBuiltDependencies;\n }\n\n if (ignoredBuiltDependencies) {\n pnpmConfig.ignoredBuiltDependencies = ignoredBuiltDependencies;\n }\n\n return {\n ...targetPackageManifest,\n pnpm: pnpmConfig,\n } as PackageManifest;\n}\n","import type { PackageScripts } from \"@pnpm/types\";\nimport { omit, pick } from \"remeda\";\nimport type { IsolateConfigResolved } from \"../config\";\nimport { usePackageManager } from \"../package-manager\";\nimport type { PackageManifest, PackagesRegistry } from \"../types\";\nimport {\n adaptManifestInternalDeps,\n adoptPnpmFieldsFromRoot,\n resolveCatalogDependencies,\n} from \"./helpers\";\n\n/**\n * Adapt the output package manifest, so that:\n *\n * - Its internal dependencies point to the isolated ./packages/* directory.\n * - The devDependencies are possibly removed\n * - Scripts are picked or omitted and ot