From ec66f018caf20549a3acf36906ed534370b179d2 Mon Sep 17 00:00:00 2001 From: Thijs Koerselman Date: Sun, 12 Jan 2025 11:03:20 +0100 Subject: [PATCH] Refactor isolate to support multiple simultaneous executions (#126) --- package.json | 2 +- src/isolate.ts | 430 +++++++++--------- src/lib/config.ts | 90 ++-- .../helpers/generate-pnpm-lockfile.ts | 6 +- src/lib/lockfile/process-lockfile.ts | 10 +- .../manifest/adapt-target-package-manifest.ts | 6 +- .../adapt-internal-package-manifests.ts | 18 +- src/lib/output/get-build-output-dir.ts | 24 +- src/lib/output/unpack-dependencies.ts | 4 +- src/lib/types.ts | 7 + src/lib/utils/index.ts | 2 +- .../{get-relative-path.ts => log-paths.ts} | 4 +- 12 files changed, 297 insertions(+), 306 deletions(-) rename src/lib/utils/{get-relative-path.ts => log-paths.ts} (60%) diff --git a/package.json b/package.json index c31e8a4..7240cbc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "isolate-package", - "version": "1.22.0", + "version": "1.23.0-1", "description": "Isolate a monorepo package with its shared dependencies to form a self-contained directory, compatible with Firebase deploy", "author": "Thijs Koerselman", "license": "MIT", diff --git a/src/isolate.ts b/src/isolate.ts index 920ae5f..07e64c7 100644 --- a/src/isolate.ts +++ b/src/isolate.ts @@ -3,10 +3,9 @@ import assert from "node:assert"; import path from "node:path"; import { unique } from "remeda"; import type { IsolateConfig } from "./lib/config"; -import { resolveConfig, setUserConfig } from "./lib/config"; +import { resolveConfig } from "./lib/config"; import { processLockfile } from "./lib/lockfile"; -import type { Logger } from "./lib/logger"; -import { setLogLevel, setLogger, useLogger } from "./lib/logger"; +import { setLogLevel, useLogger } from "./lib/logger"; import { adaptInternalPackageManifests, adaptTargetPackageManifest, @@ -25,7 +24,7 @@ import { createPackagesRegistry, listInternalPackages } from "./lib/registry"; import type { PackageManifest } from "./lib/types"; import { getDirname, - getRootRelativePath, + getRootRelativeLogPath, isRushWorkspace, readTypedJson, writeTypedYamlSync, @@ -33,223 +32,228 @@ import { const __dirname = getDirname(import.meta.url); -export async function isolate( - options: { config?: IsolateConfig; logger?: Logger } = {} -) { - if (options.logger) { - setLogger(options.logger); - } - - if (options.config) { - setUserConfig(options.config); - } - - const config = resolveConfig(); - - setLogLevel(config.logLevel); - - const log = useLogger(); - - const { version: libraryVersion } = await readTypedJson( - path.join(path.join(__dirname, "..", "package.json")) - ); - - log.info("Using isolate-package version", libraryVersion); - - /** - * If a targetPackagePath is set, we assume the configuration lives in the - * root of the workspace. If targetPackagePath is undefined (the default), we - * assume that the configuration lives in the target package directory. - */ - const targetPackageDir = config.targetPackagePath - ? path.join(process.cwd(), config.targetPackagePath) - : process.cwd(); - - const workspaceRootDir = config.targetPackagePath - ? process.cwd() - : path.join(targetPackageDir, config.workspaceRoot); - - const buildOutputDir = await getBuildOutputDir(targetPackageDir); - - assert( - fs.existsSync(buildOutputDir), - `Failed to find build output path at ${buildOutputDir}. Please make sure you build the source before isolating it.` - ); - - log.debug("Workspace root resolved to", workspaceRootDir); - log.debug( - "Isolate target package", - getRootRelativePath(targetPackageDir, workspaceRootDir) - ); - - const isolateDir = path.join(targetPackageDir, config.isolateDirName); - - log.debug( - "Isolate output directory", - getRootRelativePath(isolateDir, workspaceRootDir) - ); - - if (fs.existsSync(isolateDir)) { - await fs.remove(isolateDir); - log.debug("Cleaned the existing isolate output directory"); - } - - await fs.ensureDir(isolateDir); - - const tmpDir = path.join(isolateDir, "__tmp"); - await fs.ensureDir(tmpDir); - - const targetPackageManifest = await readTypedJson( - path.join(targetPackageDir, "package.json") - ); - - const packageManager = detectPackageManager(workspaceRootDir); - - log.debug( - "Detected package manager", - packageManager.name, - packageManager.version - ); - - if (shouldUsePnpmPack()) { - log.debug("Use PNPM pack instead of NPM pack"); - } - - /** - * Build a packages registry so we can find the workspace packages by name and - * have access to their manifest files and relative paths. - */ - const packagesRegistry = await createPackagesRegistry( - workspaceRootDir, - config.workspacePackages - ); - - const internalPackageNames = listInternalPackages( - targetPackageManifest, - packagesRegistry, - { - includeDevDependencies: config.includeDevDependencies, +export function createIsolator(config?: IsolateConfig) { + const resolvedConfig = resolveConfig(config); + + return async function isolate(): Promise { + const config = resolvedConfig; + setLogLevel(config.logLevel); + const log = useLogger(); + + const { version: libraryVersion } = await readTypedJson( + path.join(path.join(__dirname, "..", "package.json")) + ); + + log.info("Using isolate-package version", libraryVersion); + + /** + * If a targetPackagePath is set, we assume the configuration lives in the + * root of the workspace. If targetPackagePath is undefined (the default), + * we assume that the configuration lives in the target package directory. + */ + const targetPackageDir = config.targetPackagePath + ? path.join(process.cwd(), config.targetPackagePath) + : process.cwd(); + + const workspaceRootDir = config.targetPackagePath + ? process.cwd() + : path.join(targetPackageDir, config.workspaceRoot); + + const buildOutputDir = await getBuildOutputDir({ + targetPackageDir, + buildDirName: config.buildDirName, + tsconfigPath: config.tsconfigPath, + }); + + assert( + fs.existsSync(buildOutputDir), + `Failed to find build output path at ${buildOutputDir}. Please make sure you build the source before isolating it.` + ); + + log.debug("Workspace root resolved to", workspaceRootDir); + log.debug( + "Isolate target package", + getRootRelativeLogPath(targetPackageDir, workspaceRootDir) + ); + + const isolateDir = path.join(targetPackageDir, config.isolateDirName); + + log.debug( + "Isolate output directory", + getRootRelativeLogPath(isolateDir, workspaceRootDir) + ); + + if (fs.existsSync(isolateDir)) { + await fs.remove(isolateDir); + log.debug("Cleaned the existing isolate output directory"); + } + + await fs.ensureDir(isolateDir); + + const tmpDir = path.join(isolateDir, "__tmp"); + await fs.ensureDir(tmpDir); + + const targetPackageManifest = await readTypedJson( + path.join(targetPackageDir, "package.json") + ); + + const packageManager = detectPackageManager(workspaceRootDir); + + log.debug( + "Detected package manager", + packageManager.name, + packageManager.version + ); + + if (shouldUsePnpmPack()) { + log.debug("Use PNPM pack instead of NPM pack"); } - ); - - const packedFilesByName = await packDependencies({ - internalPackageNames, - packagesRegistry, - packDestinationDir: tmpDir, - }); - - await unpackDependencies( - packedFilesByName, - packagesRegistry, - tmpDir, - isolateDir - ); - - /** Adapt the manifest files for all the unpacked local dependencies */ - await adaptInternalPackageManifests( - internalPackageNames, - packagesRegistry, - isolateDir - ); - - /** Pack the target package directory, and unpack it in the isolate location */ - await processBuildOutputFiles({ - targetPackageDir, - tmpDir, - isolateDir, - }); - - /** - * Copy the target manifest file to the isolate location and adapt its - * workspace dependencies to point to the isolated packages. - */ - const outputManifest = await adaptTargetPackageManifest({ - manifest: targetPackageManifest, - packagesRegistry, - workspaceRootDir, - }); - - await writeManifest(isolateDir, outputManifest); - - /** Generate an isolated lockfile based on the original one */ - const usedFallbackToNpm = await processLockfile({ - workspaceRootDir, - isolateDir, - packagesRegistry, - internalDepPackageNames: internalPackageNames, - targetPackageDir, - targetPackageName: targetPackageManifest.name, - targetPackageManifest: outputManifest, - }); - - if (usedFallbackToNpm) { + /** - * When we fall back to NPM, we set the manifest package manager to the - * available NPM version. + * Build a packages registry so we can find the workspace packages by name + * and have access to their manifest files and relative paths. */ - const manifest = await readManifest(isolateDir); + const packagesRegistry = await createPackagesRegistry( + workspaceRootDir, + config.workspacePackages + ); + + const internalPackageNames = listInternalPackages( + targetPackageManifest, + packagesRegistry, + { + includeDevDependencies: config.includeDevDependencies, + } + ); + + const packedFilesByName = await packDependencies({ + internalPackageNames, + packagesRegistry, + packDestinationDir: tmpDir, + }); + + await unpackDependencies( + packedFilesByName, + packagesRegistry, + tmpDir, + isolateDir + ); + + /** Adapt the manifest files for all the unpacked local dependencies */ + await adaptInternalPackageManifests({ + internalPackageNames, + packagesRegistry, + isolateDir, + forceNpm: config.forceNpm, + }); + + /** Pack the target package directory, and unpack it in the isolate location */ + await processBuildOutputFiles({ + targetPackageDir, + tmpDir, + isolateDir, + }); - const npmVersion = getVersion("npm"); - manifest.packageManager = `npm@${npmVersion}`; + /** + * Copy the target manifest file to the isolate location and adapt its + * workspace dependencies to point to the isolated packages. + */ + const outputManifest = await adaptTargetPackageManifest({ + manifest: targetPackageManifest, + packagesRegistry, + workspaceRootDir, + config, + }); + + await writeManifest(isolateDir, outputManifest); + + /** Generate an isolated lockfile based on the original one */ + const usedFallbackToNpm = await processLockfile({ + workspaceRootDir, + isolateDir, + packagesRegistry, + internalDepPackageNames: internalPackageNames, + targetPackageDir, + targetPackageName: targetPackageManifest.name, + targetPackageManifest: outputManifest, + config, + }); + + if (usedFallbackToNpm) { + /** + * When we fall back to NPM, we set the manifest package manager to the + * available NPM version. + */ + const manifest = await readManifest(isolateDir); + + const npmVersion = getVersion("npm"); + manifest.packageManager = `npm@${npmVersion}`; + + await writeManifest(isolateDir, manifest); + } - await writeManifest(isolateDir, manifest); - } + if (packageManager.name === "pnpm" && !config.forceNpm) { + /** + * PNPM doesn't install dependencies of packages that are linked via link: + * or file: specifiers. It requires the directory to be configured as a + * workspace, so we copy the workspace config file to the isolate output. + * + * Rush doesn't have a pnpm-workspace.yaml file, so we generate one. + */ + if (isRushWorkspace(workspaceRootDir)) { + const packagesFolderNames = unique( + internalPackageNames.map( + (name) => path.parse(packagesRegistry[name].rootRelativeDir).dir + ) + ); + + log.debug("Generating pnpm-workspace.yaml for Rush workspace"); + log.debug("Packages folder names:", packagesFolderNames); + + const packages = packagesFolderNames.map((x) => path.join(x, "/*")); + + await writeTypedYamlSync(path.join(isolateDir, "pnpm-workspace.yaml"), { + packages, + }); + } else { + fs.copyFileSync( + path.join(workspaceRootDir, "pnpm-workspace.yaml"), + path.join(isolateDir, "pnpm-workspace.yaml") + ); + } + } - if (packageManager.name === "pnpm" && !config.forceNpm) { /** - * PNPM doesn't install dependencies of packages that are linked via link: - * or file: specifiers. It requires the directory to be configured as a - * workspace, so we copy the workspace config file to the isolate output. + * If there is an .npmrc file in the workspace root, copy it to the isolate + * because the settings there could affect how the lockfile is resolved. + * Note that .npmrc is used by both NPM and PNPM for configuration. * - * Rush doesn't have a pnpm-workspace.yaml file, so we generate one. + * See also: https://pnpm.io/npmrc */ - if (isRushWorkspace(workspaceRootDir)) { - const packagesFolderNames = unique( - internalPackageNames.map( - (name) => path.parse(packagesRegistry[name].rootRelativeDir).dir - ) - ); - - log.debug("Generating pnpm-workspace.yaml for Rush workspace"); - log.debug("Packages folder names:", packagesFolderNames); - - const packages = packagesFolderNames.map((x) => path.join(x, "/*")); - - await writeTypedYamlSync(path.join(isolateDir, "pnpm-workspace.yaml"), { - packages, - }); - } else { - fs.copyFileSync( - path.join(workspaceRootDir, "pnpm-workspace.yaml"), - path.join(isolateDir, "pnpm-workspace.yaml") - ); + const npmrcPath = path.join(workspaceRootDir, ".npmrc"); + + if (fs.existsSync(npmrcPath)) { + fs.copyFileSync(npmrcPath, path.join(isolateDir, ".npmrc")); + log.debug("Copied .npmrc file to the isolate output"); } - } - /** - * If there is an .npmrc file in the workspace root, copy it to the isolate - * because the settings there could affect how the lockfile is resolved. Note - * that .npmrc is used by both NPM and PNPM for configuration. - * - * See also: https://pnpm.io/npmrc - */ - const npmrcPath = path.join(workspaceRootDir, ".npmrc"); - - if (fs.existsSync(npmrcPath)) { - fs.copyFileSync(npmrcPath, path.join(isolateDir, ".npmrc")); - log.debug("Copied .npmrc file to the isolate output"); - } - - /** - * Clean up. Only so this in the happy path, so we can look at the temp folder - * when thing go wrong. - */ - log.debug( - "Deleting temp directory", - getRootRelativePath(tmpDir, workspaceRootDir) - ); - await fs.remove(tmpDir); - - log.info("Isolate completed at", isolateDir); - - return isolateDir; + + /** + * Clean up. Only do this when things succeed, so we can look at the temp + * folder in case something goes wrong. + */ + log.debug( + "Deleting temp directory", + getRootRelativeLogPath(tmpDir, workspaceRootDir) + ); + await fs.remove(tmpDir); + + log.info("Isolate completed at", isolateDir); + + return isolateDir; + }; +} + +// Keep the original function for backward compatibility +export async function isolate(config?: IsolateConfig): Promise { + return createIsolator(config)(); } diff --git a/src/lib/config.ts b/src/lib/config.ts index b17b836..4673ee8 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -1,5 +1,4 @@ import fs from "fs-extra"; -import assert from "node:assert"; import path from "node:path"; import { isEmpty } from "remeda"; import { setLogLevel, useLogger } from "./logger"; @@ -39,90 +38,55 @@ const configDefaults: IsolateConfigResolved = { omitPackageManager: false, }; -/** - * Only initialize the configuration once, and keeping it here for subsequent - * calls to getConfig. - */ -let _resolvedConfig: IsolateConfigResolved | undefined; - -let _user_defined_config: IsolateConfig | undefined; - const validConfigKeys = Object.keys(configDefaults); - const CONFIG_FILE_NAME = "isolate.config.json"; export type LogLevel = IsolateConfigResolved["logLevel"]; -export function setUserConfig(config: IsolateConfig) { - _user_defined_config = config; - - if (config.logLevel) { - setLogLevel(config.logLevel); - } +function loadConfigFromFile(): IsolateConfig { + const configFilePath = path.join(process.cwd(), CONFIG_FILE_NAME); + return fs.existsSync(configFilePath) + ? readTypedJsonSync(configFilePath) + : {}; } -export function useConfig() { - if (_resolvedConfig) { - return _resolvedConfig; - } else { - throw new Error("Called useConfig before config was made available"); - } -} +function validateConfig(config: IsolateConfig) { + const log = useLogger(); + const foreignKeys = Object.keys(config).filter( + (key) => !validConfigKeys.includes(key) + ); -/** - * Resolve configuration based on user config and defaults. If setConfig was - * called before this, it does not attempt to read a config file from disk. - */ -export function resolveConfig(): IsolateConfigResolved { - if (_resolvedConfig) { - return _resolvedConfig; + if (!isEmpty(foreignKeys)) { + log.warn(`Found invalid config settings:`, foreignKeys.join(", ")); } +} +export function resolveConfig( + initialConfig?: IsolateConfig +): IsolateConfigResolved { setLogLevel(process.env.DEBUG_ISOLATE_CONFIG ? "debug" : "info"); - const log = useLogger(); - const configFilePath = path.join(process.cwd(), CONFIG_FILE_NAME); + const userConfig = initialConfig ?? loadConfigFromFile(); - if (_user_defined_config) { - log.debug(`Using user defined config:`, inspectValue(_user_defined_config)); + if (initialConfig) { + log.debug(`Using user defined config:`, inspectValue(initialConfig)); } else { - log.debug(`Attempting to load config from ${configFilePath}`); - - _user_defined_config = fs.existsSync(configFilePath) - ? readTypedJsonSync(configFilePath) - : {}; + log.debug(`Loaded config from ${CONFIG_FILE_NAME}`); } - const foreignKeys = Object.keys(_user_defined_config).filter( - (key) => !validConfigKeys.includes(key) - ); + validateConfig(userConfig); - if (!isEmpty(foreignKeys)) { - log.warn(`Found invalid config settings:`, foreignKeys.join(", ")); + if (userConfig.logLevel) { + setLogLevel(userConfig.logLevel); } - const config = Object.assign( - {}, - configDefaults, - _user_defined_config - ) satisfies IsolateConfigResolved; + const config = { + ...configDefaults, + ...userConfig, + } satisfies IsolateConfigResolved; log.debug("Using configuration:", inspectValue(config)); - _resolvedConfig = config; return config; } - -/** - * Get only the configuration that the user set explicitly in the config file or - * passed via arguments to isolate(). - */ -export function getUserDefinedConfig(): IsolateConfig { - assert( - _user_defined_config, - "Called getUserDefinedConfig before user config was made available" - ); - - return _user_defined_config; -} diff --git a/src/lib/lockfile/helpers/generate-pnpm-lockfile.ts b/src/lib/lockfile/helpers/generate-pnpm-lockfile.ts index 34556a5..c2f8f35 100644 --- a/src/lib/lockfile/helpers/generate-pnpm-lockfile.ts +++ b/src/lib/lockfile/helpers/generate-pnpm-lockfile.ts @@ -13,7 +13,6 @@ import { import { pruneLockfile as pruneLockfile_v8 } from "pnpm_prune_lockfile_v8"; import { pruneLockfile as pruneLockfile_v9 } from "pnpm_prune_lockfile_v9"; import { pick } from "remeda"; -import { useConfig } from "~/lib/config"; import { useLogger } from "~/lib/logger"; import type { PackageManifest, PackagesRegistry } from "~/lib/types"; import { getErrorMessage, isRushWorkspace } from "~/lib/utils"; @@ -27,6 +26,8 @@ export async function generatePnpmLockfile({ packagesRegistry, targetPackageManifest, majorVersion, + includeDevDependencies, + includePatchedDependencies, }: { workspaceRootDir: string; targetPackageDir: string; @@ -35,6 +36,8 @@ export async function generatePnpmLockfile({ packagesRegistry: PackagesRegistry; targetPackageManifest: PackageManifest; majorVersion: number; + includeDevDependencies: boolean; + includePatchedDependencies: boolean; }) { /** * For now we will assume that the lockfile format might not change in the @@ -43,7 +46,6 @@ export async function generatePnpmLockfile({ */ const useVersion9 = majorVersion >= 9; - const { includeDevDependencies, includePatchedDependencies } = useConfig(); const log = useLogger(); log.debug("Generating PNPM lockfile..."); diff --git a/src/lib/lockfile/process-lockfile.ts b/src/lib/lockfile/process-lockfile.ts index 4aa80d4..332efc0 100644 --- a/src/lib/lockfile/process-lockfile.ts +++ b/src/lib/lockfile/process-lockfile.ts @@ -1,4 +1,4 @@ -import { useConfig } from "../config"; +import type { IsolateConfigResolved } from "../config"; import { useLogger } from "../logger"; import { usePackageManager } from "../package-manager"; import type { PackageManifest, PackagesRegistry } from "../types"; @@ -22,6 +22,7 @@ export async function processLockfile({ internalDepPackageNames, targetPackageDir, targetPackageManifest, + config, }: { workspaceRootDir: string; packagesRegistry: PackagesRegistry; @@ -30,12 +31,11 @@ export async function processLockfile({ targetPackageDir: string; targetPackageName: string; targetPackageManifest: PackageManifest; + config: IsolateConfigResolved; }) { const log = useLogger(); - const { forceNpm } = useConfig(); - - if (forceNpm) { + if (config.forceNpm) { log.info("Forcing to use NPM for isolate output"); await generateNpmLockfile({ @@ -88,6 +88,8 @@ export async function processLockfile({ packagesRegistry, targetPackageManifest, majorVersion, + includeDevDependencies: config.includeDevDependencies, + includePatchedDependencies: config.includePatchedDependencies, }); break; } diff --git a/src/lib/manifest/adapt-target-package-manifest.ts b/src/lib/manifest/adapt-target-package-manifest.ts index 05a2a98..5a38970 100644 --- a/src/lib/manifest/adapt-target-package-manifest.ts +++ b/src/lib/manifest/adapt-target-package-manifest.ts @@ -1,6 +1,6 @@ import type { PackageScripts } from "@pnpm/types"; import { omit, pick } from "remeda"; -import { useConfig } from "../config"; +import type { IsolateConfigResolved } from "../config"; import { usePackageManager } from "../package-manager"; import type { PackageManifest, PackagesRegistry } from "../types"; import { adaptManifestInternalDeps, adoptPnpmFieldsFromRoot } from "./helpers"; @@ -16,10 +16,12 @@ export async function adaptTargetPackageManifest({ manifest, packagesRegistry, workspaceRootDir, + config, }: { manifest: PackageManifest; packagesRegistry: PackagesRegistry; workspaceRootDir: string; + config: IsolateConfigResolved; }): Promise { const packageManager = usePackageManager(); const { @@ -28,7 +30,7 @@ export async function adaptTargetPackageManifest({ omitFromScripts, omitPackageManager, forceNpm, - } = useConfig(); + } = config; /** Dev dependencies are omitted by default */ const inputManifest = includeDevDependencies diff --git a/src/lib/manifest/helpers/adapt-internal-package-manifests.ts b/src/lib/manifest/helpers/adapt-internal-package-manifests.ts index 5b5dcef..ed5e309 100644 --- a/src/lib/manifest/helpers/adapt-internal-package-manifests.ts +++ b/src/lib/manifest/helpers/adapt-internal-package-manifests.ts @@ -1,6 +1,5 @@ import path from "node:path"; import { omit } from "remeda"; -import { useConfig } from "~/lib/config"; import { usePackageManager } from "~/lib/package-manager"; import type { PackagesRegistry } from "~/lib/types"; import { writeManifest } from "../io"; @@ -11,13 +10,18 @@ import { adaptManifestInternalDeps } from "./adapt-manifest-internal-deps"; * target package), so that their dependencies point to the other isolated * packages in the same folder. */ -export async function adaptInternalPackageManifests( - internalPackageNames: string[], - packagesRegistry: PackagesRegistry, - isolateDir: string -) { +export async function adaptInternalPackageManifests({ + internalPackageNames, + packagesRegistry, + isolateDir, + forceNpm, +}: { + internalPackageNames: string[]; + packagesRegistry: PackagesRegistry; + isolateDir: string; + forceNpm: boolean; +}) { const packageManager = usePackageManager(); - const { forceNpm } = useConfig(); await Promise.all( internalPackageNames.map(async (packageName) => { diff --git a/src/lib/output/get-build-output-dir.ts b/src/lib/output/get-build-output-dir.ts index 55485de..553d3e5 100644 --- a/src/lib/output/get-build-output-dir.ts +++ b/src/lib/output/get-build-output-dir.ts @@ -1,21 +1,27 @@ import { getTsconfig } from "get-tsconfig"; import path from "node:path"; import outdent from "outdent"; -import { useConfig } from "../config"; import { useLogger } from "../logger"; -export async function getBuildOutputDir(targetPackageDir: string) { - const config = useConfig(); +export async function getBuildOutputDir({ + targetPackageDir, + buildDirName, + tsconfigPath, +}: { + targetPackageDir: string; + buildDirName?: string; + tsconfigPath: string; +}) { const log = useLogger(); - if (config.buildDirName) { - log.debug("Using buildDirName from config:", config.buildDirName); - return path.join(targetPackageDir, config.buildDirName); + if (buildDirName) { + log.debug("Using buildDirName from config:", buildDirName); + return path.join(targetPackageDir, buildDirName); } - const tsconfigPath = path.join(targetPackageDir, config.tsconfigPath); + const fullTsconfigPath = path.join(targetPackageDir, tsconfigPath); - const tsconfig = getTsconfig(tsconfigPath); + const tsconfig = getTsconfig(fullTsconfigPath); if (tsconfig) { log.debug("Found tsconfig at:", tsconfig.path); @@ -30,7 +36,7 @@ export async function getBuildOutputDir(targetPackageDir: string) { `); } } else { - log.warn("Failed to find tsconfig at:", tsconfigPath); + log.warn("Failed to find tsconfig at:", fullTsconfigPath); throw new Error(outdent` Failed to infer the build output directory from either the isolate config buildDirName or a Typescript config file. See the documentation on how to configure one of these options. diff --git a/src/lib/output/unpack-dependencies.ts b/src/lib/output/unpack-dependencies.ts index 29f5360..91ba232 100644 --- a/src/lib/output/unpack-dependencies.ts +++ b/src/lib/output/unpack-dependencies.ts @@ -2,7 +2,7 @@ import fs from "fs-extra"; import path, { join } from "node:path"; import { useLogger } from "../logger"; import type { PackagesRegistry } from "../types"; -import { getIsolateRelativePath, unpack } from "../utils"; +import { getIsolateRelativeLogPath, unpack } from "../utils"; export async function unpackDependencies( packedFilesByName: Record, @@ -30,7 +30,7 @@ export async function unpackDependencies( }); log.debug( - `Moved package files to ${getIsolateRelativePath( + `Moved package files to ${getIsolateRelativeLogPath( destinationDir, isolateDir )}` diff --git a/src/lib/types.ts b/src/lib/types.ts index a91127f..7a75b32 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -16,3 +16,10 @@ export type WorkspacePackageInfo = { }; export type PackagesRegistry = Record; + +export type FirebaseFunctionsConfig = { + source: string; + runtime?: string; + predeploy?: string[]; + codebase?: string; +}; diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts index d6ea08d..f4e011a 100644 --- a/src/lib/utils/index.ts +++ b/src/lib/utils/index.ts @@ -1,11 +1,11 @@ export * from "./filter-object-undefined"; export * from "./get-dirname"; export * from "./get-error-message"; -export * from "./get-relative-path"; export * from "./inspect-value"; export * from "./is-present"; export * from "./is-rush-workspace"; export * from "./json"; +export * from "./log-paths"; export * from "./pack"; export * from "./unpack"; export * from "./yaml"; diff --git a/src/lib/utils/get-relative-path.ts b/src/lib/utils/log-paths.ts similarity index 60% rename from src/lib/utils/get-relative-path.ts rename to src/lib/utils/log-paths.ts index 78bb5cb..86a568c 100644 --- a/src/lib/utils/get-relative-path.ts +++ b/src/lib/utils/log-paths.ts @@ -1,12 +1,12 @@ import { join } from "node:path"; -export function getRootRelativePath(path: string, rootPath: string) { +export function getRootRelativeLogPath(path: string, rootPath: string) { const strippedPath = path.replace(rootPath, ""); return join("(root)", strippedPath); } -export function getIsolateRelativePath(path: string, isolatePath: string) { +export function getIsolateRelativeLogPath(path: string, isolatePath: string) { const strippedPath = path.replace(isolatePath, ""); return join("(isolate)", strippedPath);